Merge "Change handling logic in SystemAudioAutoInitiationAction"
diff --git a/Android.bp b/Android.bp
index b4ea61a..383f58f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -506,11 +506,14 @@
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
+ "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
"telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl",
"telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
+ "telephony/java/android/telephony/mbms/IGroupCallCallback.aidl",
"telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
"telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
+ "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
"telephony/java/android/telephony/INetworkService.aidl",
"telephony/java/android/telephony/INetworkServiceCallback.aidl",
"telephony/java/com/android/ims/internal/IImsCallSession.aidl",
@@ -547,6 +550,7 @@
"telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
"telephony/java/com/android/internal/telephony/ISms.aidl",
"telephony/java/com/android/internal/telephony/ISub.aidl",
+ "telephony/java/com/android/internal/telephony/IAns.aidl",
"telephony/java/com/android/internal/telephony/ITelephony.aidl",
"telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
"telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
@@ -597,6 +601,7 @@
":netd_aidl",
":vold_aidl",
":installd_aidl",
+ ":dumpstate_aidl",
"lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
"lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
@@ -643,6 +648,7 @@
include_dirs: [
"system/update_engine/binder_bindings",
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"frameworks/av/camera/aidl",
"frameworks/av/media/libaudioclient/aidl",
"frameworks/native/aidl/gui",
@@ -665,9 +671,6 @@
no_framework_libs: true,
libs: [
- "conscrypt",
- "okhttp",
- "bouncycastle",
"ext",
],
@@ -686,7 +689,9 @@
"android.hardware.vibrator-V1.2-java",
"android.hardware.wifi-V1.0-java-constants",
"android.hardware.radio-V1.0-java",
+ "android.hardware.radio-V1.3-java",
"android.hardware.usb.gadget-V1.0-java",
+ "netd_aidl_interface-java",
],
// Loaded with System.loadLibrary by android.view.textclassifier
@@ -795,7 +800,7 @@
java_library {
name: "ext",
installable: true,
- no_framework_libs: true,
+ sdk_version: "core_current",
static_libs: [
"libphonenumber-platform",
"nist-sip",
@@ -1070,53 +1075,62 @@
"-federate SupportLib https://developer.android.com " +
"-federationapi SupportLib $(location current/support-api.txt) "
-doc_defaults {
- name: "api-stubs-default",
- srcs: [
- ":opt-telephony-srcs",
- ":opt-net-voip-srcs",
- ":openjdk_javadoc_files",
- ":non_openjdk_javadoc_files",
- ":android_icu4j_src_files_for_docs",
- ],
- 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",
- ],
- local_sourcepaths: frameworks_base_subdirs,
- html_dirs: [
- "docs/html",
- ],
- knowntags: [
- "docs/knowntags.txt",
- ":known-oj-tags",
- ],
- 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",
- ],
- resourcesdir: "docs/html/reference/images",
- resourcesoutdir: "reference/android/images",
- installable: false,
-}
+framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+ "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
+ "-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) "
-doc_defaults {
- name: "framework-docs-default",
+framework_docs_only_libs = [
+ "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",
@@ -1130,47 +1144,26 @@
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",
- ],
+ libs: framework_docs_only_libs,
local_sourcepaths: frameworks_base_subdirs,
+ create_doc_stubs: true,
+ annotations_enabled: true,
+ api_levels_annotations_enabled: true,
+ api_levels_annotations_dirs: [
+ "sdk-dir",
+ "api-versions-jars-dir",
+ ],
+ previous_api: ":last-released-public-api",
+ merge_annotations_dirs: [
+ "metalava-manual",
+ "ojluni-annotated-sdk-stubs",
+ ],
+}
+
+doc_defaults {
+ name: "framework-docs-default",
+ libs: framework_docs_only_libs +
+ ["stub-annotations"],
html_dirs: [
"docs/html",
],
@@ -1191,22 +1184,12 @@
],
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: [
@@ -1236,52 +1219,92 @@
previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
- "ojluni-annotated-stubs",
+ "ojluni-annotated-sdk-stubs",
],
+ api_levels_annotations_enabled: true,
+ api_levels_annotations_dirs: [
+ "sdk-dir",
+ "api-versions-jars-dir",
+ ],
+}
+
+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",
}
droiddoc {
+ // Please sync with android-api-council@ before making any changes for the name property below.
+ // Since there's cron jobs that fetch offline-sdk-referenceonly-docs-docs.zip periodically.
+ // See b/116221385 for reference.
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",
}
droiddoc {
+ // Please sync with android-api-council@ before making any changes for the name property below.
+ // Since there's cron jobs that fetch offline-system-sdk-referenceonly-docs-docs.zip periodically.
+ // See b/116221385 for reference.
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",
@@ -1290,12 +1313,15 @@
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 " +
@@ -1316,14 +1342,16 @@
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 " +
@@ -1349,12 +1377,15 @@
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 " +
@@ -1375,11 +1406,14 @@
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 " +
@@ -1389,11 +1423,14 @@
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 ",
@@ -1402,12 +1439,15 @@
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 " +
@@ -1428,13 +1468,16 @@
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",
@@ -1452,10 +1495,15 @@
"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-sdk-stubs",
+ ],
+ args: " --show-annotation android.annotation.SystemApi",
}
java_library_static {
@@ -1482,23 +1530,17 @@
}
-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 {
@@ -1518,7 +1560,6 @@
"core/java/org/apache/http/params/CoreConnectionPNames.java",
"core/java/org/apache/http/params/HttpConnectionParams.java",
"core/java/org/apache/http/params/HttpParams.java",
- "core/java/android/net/http/HttpResponseCache.java",
"core/java/android/net/http/SslCertificate.java",
"core/java/android/net/http/SslError.java",
"core/java/com/android/internal/util/HexDump.java",
@@ -1545,6 +1586,7 @@
removed_api_file: "api/removed.txt",
},
},
+ jdiff_enabled: true,
}
droidstubs {
@@ -1569,6 +1611,7 @@
removed_api_file: "api/system-removed.txt",
},
},
+ jdiff_enabled: true,
}
droidstubs {
diff --git a/Android.mk b/Android.mk
index 5c4c237..770ec20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -53,265 +53,16 @@
cat $^ | sort -u > $@.tmp
$(call commit-change-for-toc,$@)
-# the documentation
-# ============================================================
-
-# TODO: deal with com/google/android/googleapps
-packages_to_document := \
- android \
- javax/microedition/khronos \
- org/apache/http/conn \
- org/apache/http/params \
-
-# include definition of libcore_to_document
-include libcore/Docs.mk
-
-non_base_dirs := \
- ../opt/telephony/src/java/android/telephony \
- ../opt/telephony/src/java/android/telephony/gsm \
- ../opt/net/voip/src/java/android/net/rtp \
- ../opt/net/voip/src/java/android/net/sip \
-
-# Find all files in specific directories (relative to frameworks/base)
-# to document and check apis
-files_to_check_apis := \
- $(call find-other-java-files, \
- $(non_base_dirs) \
- )
-
-# Find all files in specific packages that were used to compile
-# framework.jar to document and check apis
-files_to_check_apis += \
- $(addprefix ../../,\
- $(filter \
- $(foreach dir,$(FRAMEWORKS_BASE_JAVA_SRC_DIRS),\
- $(foreach package,$(packages_to_document),\
- $(dir)/$(package)/%.java)),\
- $(SOONG_FRAMEWORK_SRCS)))
-
-# Find all generated files that were used to compile framework.jar
-files_to_check_apis_generated := \
- $(filter $(OUT_DIR)/%,\
- $(SOONG_FRAMEWORK_SRCS))
-
-# These are relative to frameworks/base
-# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
-files_to_document := \
- $(files_to_check_apis) \
- $(call find-other-java-files,\
- test-base/src \
- test-mock/src \
- test-runner/src)
-
-# These are relative to frameworks/base
-html_dirs := \
- $(FRAMEWORKS_BASE_SUBDIRS) \
- $(non_base_dirs) \
-
-# Common sources for doc check and api check
-common_src_files := \
- $(call find-other-html-files, $(html_dirs)) \
- $(addprefix ../../, $(libcore_to_document)) \
-
-# These are relative to frameworks/base
-framework_docs_LOCAL_SRC_FILES := \
- $(files_to_document) \
- $(common_src_files) \
-
-# These are relative to frameworks/base
-framework_docs_LOCAL_API_CHECK_SRC_FILES := \
- $(files_to_check_apis) \
- $(common_src_files) \
-
# This is used by ide.mk as the list of source files that are
# always included.
INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
-framework_docs_LOCAL_DROIDDOC_SOURCE_PATH := \
- $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
-
-framework_docs_LOCAL_SRCJARS := $(SOONG_FRAMEWORK_SRCJARS)
-
-framework_docs_LOCAL_GENERATED_SOURCES := \
- $(libcore_to_document_generated) \
- $(files_to_check_apis_generated) \
-
-framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
- core-oj \
- core-libart \
- conscrypt \
- bouncycastle \
- okhttp \
- ext \
- framework \
- voip-common \
-
-# Platform docs can refer to Support Library APIs, but we don't actually build
-# them as part of the docs target, so we need to include them on the classpath.
-framework_docs_LOCAL_JAVA_LIBRARIES := \
- $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES) \
- $(FRAMEWORKS_SUPPORT_JAVA_LIBRARIES)
-
-framework_docs_LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
-# The since flag (-since N.xml API_LEVEL) is used to add API Level information
-# to the reference documentation. Must be in order of oldest to newest.
-#
-# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
-# not be referenced in the documentation.
-framework_docs_LOCAL_DROIDDOC_OPTIONS := \
- -android \
- -knowntags ./frameworks/base/docs/knowntags.txt \
- -knowntags ./libcore/known_oj_tags.txt \
- -manifest ./frameworks/base/core/res/AndroidManifest.xml \
- -hidePackage com.android.internal \
- -hidePackage com.android.internal.util \
- -hidePackage com.android.okhttp \
- -hidePackage com.android.org.conscrypt \
- -hidePackage com.android.server
-
-# Convert an sdk level to a "since" argument.
-since-arg = -since $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(1)/public/api/android.$(2)) $(1)
-
-finalized_xml_sdks := $(call numerically_sort,\
- $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/public/api/android.xml,%,\
- $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/public/api/android.xml)))
-finalized_txt_sdks := $(call numerically_sort,\
- $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/public/api/android.txt,%,\
- $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/public/api/android.txt)))
-
-framework_docs_LOCAL_DROIDDOC_OPTIONS += $(foreach sdk,$(finalized_xml_sdks),$(call since-arg,$(sdk),xml))
-framework_docs_LOCAL_DROIDDOC_OPTIONS += $(foreach sdk,$(finalized_txt_sdks),$(call since-arg,$(sdk),txt))
-ifneq ($(PLATFORM_VERSION_CODENAME),REL)
- framework_docs_LOCAL_DROIDDOC_OPTIONS += \
- -since ./frameworks/base/api/current.txt $(PLATFORM_VERSION_CODENAME)
-endif
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
- -werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
- -overview $(LOCAL_PATH)/core/java/overview.html
-
-framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
- $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)
-
-framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \
- $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-
-framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES := \
- frameworks/base/docs/knowntags.txt \
- $(libcore_to_document_generated)
-
-samples_dir := development/samples/browseable
-
-# Whitelist of valid groups, used for default TOC grouping. Each sample must
-# belong to one (and only one) group. Assign samples to groups by setting
-# a sample.group var to one of these groups in the sample's _index.jd.
-sample_groups := -samplegroup Admin \
- -samplegroup Background \
- -samplegroup Connectivity \
- -samplegroup Content \
- -samplegroup Input \
- -samplegroup Media \
- -samplegroup Notification \
- -samplegroup RenderScript \
- -samplegroup Security \
- -samplegroup Sensors \
- -samplegroup System \
- -samplegroup Testing \
- -samplegroup UI \
- -samplegroup Views \
- -samplegroup Wearable
-
-## SDK version identifiers used in the published docs
- # major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=7.0
- # release version (ie "Release x") (full releases only)
-framework_docs_SDK_REL_ID:=1
-
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
- -hdf dac true \
- -hdf sdk.codename O \
- -hdf sdk.preview.version 1 \
- -hdf sdk.version $(framework_docs_SDK_VERSION) \
- -hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
- -hdf sdk.preview 0 \
- -resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
- -resourcesoutdir reference/android/images/
-
-# Federate Support Library references against local API file.
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
- -federate SupportLib https://developer.android.com \
- -federationapi SupportLib prebuilts/sdk/current/support-api.txt
-
-# Federate AndroidX references against local API file.
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
- -federate AndroidX https://developer.android.com \
- -federationapi AndroidX prebuilts/sdk/current/androidx-api.txt
-
-# Get the highest numbered api txt for the given api level.
-# $(1): the api level (e.g. public, system)
-define highest_sdk_txt
-$(HISTORICAL_SDK_VERSIONS_ROOT)/$(lastword $(call numerically_sort, \
- $(patsubst \
- $(HISTORICAL_SDK_VERSIONS_ROOT)/%,\
- %,\
- $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/$(1)/api/android.txt)\
- ) \
-))
-endef
-
-# ==== Public API diff ===========================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
- $(INTERNAL_PLATFORM_API_FILE)
-
-LOCAL_MODULE := offline-sdk-referenceonly
-
-# Basename, because apidiff adds .txt internally.
-LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,public))
-LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_API_FILE))
-
-include $(BUILD_APIDIFF)
-
-# Hack to get diffs included in docs output
-out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
-$(out_zip): $(full_target)
-
-# ==== System API diff ===========================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
- $(INTERNAL_PLATFORM_SYSTEM_API_FILE)
-
-LOCAL_MODULE := offline-system-sdk-referenceonly
-
-# Basename, because apidiff adds .txt internally.
-LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,system))
-LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_SYSTEM_API_FILE))
-
-include $(BUILD_APIDIFF)
-
-# Hack to get diffs included in docs output
-out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
-$(out_zip): $(full_target)
-
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE):apistubs/android/public/api/android.txt)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE):apistubs/android/system/api/android.txt)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE):apistubs/android/test/api/android.txt)
# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
@@ -336,6 +87,7 @@
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
+ frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
frameworks/base/config/hiddenapi-force-blacklist.txt \
$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
@@ -347,6 +99,7 @@
--input-greylists \
frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
+ frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
<(comm -12 <(sort $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \
$(PRIVATE_GREYLIST_INPUTS) \
@@ -360,6 +113,17 @@
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA): \
+ frameworks/base/tools/hiddenapi/merge_csv.py \
+ $(PRIVATE_METADATA_INPUTS)
+ frameworks/base/tools/hiddenapi/merge_csv.py $(PRIVATE_METADATA_INPUTS) > $@
+
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA))
+
# Include subdirectory makefiles
# ============================================================
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2247e43..6deda0c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -247,6 +247,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.mediadrm.signer.jar)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.location.provider.jar)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.future.usb.accessory.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.media.remotedisplay.jar)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
# ******************************************************************
diff --git a/api/current.txt b/api/current.txt
index 2a1295c..b691ef3 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
field public static final java.lang.String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
+ field public static final java.lang.String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -7698,7 +7699,9 @@
method public boolean isMultipleAdvertisementSupported();
method public boolean isOffloadedFilteringSupported();
method public boolean isOffloadedScanBatchingSupported();
+ method public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
+ method public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
method public boolean setName(java.lang.String);
method public boolean startDiscovery();
@@ -8066,7 +8069,9 @@
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
method public boolean createBond();
+ method public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+ method public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public int describeContents();
method public boolean fetchUuidsWithSdp();
@@ -8482,6 +8487,7 @@
method public android.bluetooth.BluetoothSocket accept() throws java.io.IOException;
method public android.bluetooth.BluetoothSocket accept(int) throws java.io.IOException;
method public void close() throws java.io.IOException;
+ method public int getPsm();
}
public final class BluetoothSocket implements java.io.Closeable {
@@ -18481,6 +18487,114 @@
method public java.lang.CharSequence getName();
}
+ public class Bidi {
+ ctor public Bidi();
+ ctor public Bidi(int, int);
+ ctor public Bidi(java.lang.String, int);
+ ctor public Bidi(java.text.AttributedCharacterIterator);
+ ctor public Bidi(char[], int, byte[], int, int, int);
+ method public boolean baseIsLeftToRight();
+ method public int countParagraphs();
+ method public int countRuns();
+ method public android.icu.text.Bidi createLineBidi(int, int);
+ method public static byte getBaseDirection(java.lang.CharSequence);
+ method public int getBaseLevel();
+ method public android.icu.text.BidiClassifier getCustomClassifier();
+ method public int getCustomizedClass(int);
+ method public byte getDirection();
+ method public int getLength();
+ method public byte getLevelAt(int);
+ method public byte[] getLevels();
+ method public int getLogicalIndex(int);
+ method public int[] getLogicalMap();
+ method public android.icu.text.BidiRun getLogicalRun(int);
+ method public byte getParaLevel();
+ method public android.icu.text.BidiRun getParagraph(int);
+ method public android.icu.text.BidiRun getParagraphByIndex(int);
+ method public int getParagraphIndex(int);
+ method public int getProcessedLength();
+ method public int getReorderingMode();
+ method public int getReorderingOptions();
+ method public int getResultLength();
+ method public int getRunCount();
+ method public int getRunLevel(int);
+ method public int getRunLimit(int);
+ method public int getRunStart(int);
+ method public char[] getText();
+ method public java.lang.String getTextAsString();
+ method public int getVisualIndex(int);
+ method public int[] getVisualMap();
+ method public android.icu.text.BidiRun getVisualRun(int);
+ method public static int[] invertMap(int[]);
+ method public boolean isInverse();
+ method public boolean isLeftToRight();
+ method public boolean isMixed();
+ method public boolean isOrderParagraphsLTR();
+ method public boolean isRightToLeft();
+ method public void orderParagraphsLTR(boolean);
+ method public static int[] reorderLogical(byte[]);
+ method public static int[] reorderVisual(byte[]);
+ method public static void reorderVisually(byte[], int, java.lang.Object[], int, int);
+ method public static boolean requiresBidi(char[], int, int);
+ method public void setContext(java.lang.String, java.lang.String);
+ method public void setCustomClassifier(android.icu.text.BidiClassifier);
+ method public void setInverse(boolean);
+ method public android.icu.text.Bidi setLine(int, int);
+ method public void setPara(java.lang.String, byte, byte[]);
+ method public void setPara(char[], byte, byte[]);
+ method public void setPara(java.text.AttributedCharacterIterator);
+ method public void setReorderingMode(int);
+ method public void setReorderingOptions(int);
+ method public java.lang.String writeReordered(int);
+ method public static java.lang.String writeReverse(java.lang.String, int);
+ field public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = 126; // 0x7e
+ field public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = 127; // 0x7f
+ field public static final int DIRECTION_LEFT_TO_RIGHT = 0; // 0x0
+ field public static final int DIRECTION_RIGHT_TO_LEFT = 1; // 0x1
+ field public static final short DO_MIRRORING = 2; // 0x2
+ field public static final short INSERT_LRM_FOR_NUMERIC = 4; // 0x4
+ field public static final short KEEP_BASE_COMBINING = 1; // 0x1
+ field public static final byte LEVEL_DEFAULT_LTR = 126; // 0x7e
+ field public static final byte LEVEL_DEFAULT_RTL = 127; // 0x7f
+ field public static final byte LEVEL_OVERRIDE = -128; // 0xffffff80
+ field public static final byte LTR = 0; // 0x0
+ field public static final int MAP_NOWHERE = -1; // 0xffffffff
+ field public static final byte MAX_EXPLICIT_LEVEL = 125; // 0x7d
+ field public static final byte MIXED = 2; // 0x2
+ field public static final byte NEUTRAL = 3; // 0x3
+ field public static final int OPTION_DEFAULT = 0; // 0x0
+ field public static final int OPTION_INSERT_MARKS = 1; // 0x1
+ field public static final int OPTION_REMOVE_CONTROLS = 2; // 0x2
+ field public static final int OPTION_STREAMING = 4; // 0x4
+ field public static final short OUTPUT_REVERSE = 16; // 0x10
+ field public static final short REMOVE_BIDI_CONTROLS = 8; // 0x8
+ field public static final short REORDER_DEFAULT = 0; // 0x0
+ field public static final short REORDER_GROUP_NUMBERS_WITH_R = 2; // 0x2
+ field public static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; // 0x6
+ field public static final short REORDER_INVERSE_LIKE_DIRECT = 5; // 0x5
+ field public static final short REORDER_INVERSE_NUMBERS_AS_L = 4; // 0x4
+ field public static final short REORDER_NUMBERS_SPECIAL = 1; // 0x1
+ field public static final short REORDER_RUNS_ONLY = 3; // 0x3
+ field public static final byte RTL = 1; // 0x1
+ }
+
+ public class BidiClassifier {
+ ctor public BidiClassifier(java.lang.Object);
+ method public int classify(int);
+ method public java.lang.Object getContext();
+ method public void setContext(java.lang.Object);
+ }
+
+ public class BidiRun {
+ method public byte getDirection();
+ method public byte getEmbeddingLevel();
+ method public int getLength();
+ method public int getLimit();
+ method public int getStart();
+ method public boolean isEvenRun();
+ method public boolean isOddRun();
+ }
+
public abstract class BreakIterator implements java.lang.Cloneable {
ctor protected BreakIterator();
method public java.lang.Object clone();
@@ -18532,6 +18646,37 @@
field public static final int WORD_NUMBER_LIMIT = 200; // 0xc8
}
+ public abstract class CaseMap {
+ method public static android.icu.text.CaseMap.Fold fold();
+ method public abstract android.icu.text.CaseMap omitUnchangedText();
+ method public static android.icu.text.CaseMap.Lower toLower();
+ method public static android.icu.text.CaseMap.Title toTitle();
+ method public static android.icu.text.CaseMap.Upper toUpper();
+ }
+
+ public static final class CaseMap.Fold extends android.icu.text.CaseMap {
+ method public <A extends java.lang.Appendable> A apply(java.lang.CharSequence, A, android.icu.text.Edits);
+ method public android.icu.text.CaseMap.Fold omitUnchangedText();
+ method public android.icu.text.CaseMap.Fold turkic();
+ }
+
+ public static final class CaseMap.Lower extends android.icu.text.CaseMap {
+ method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+ method public android.icu.text.CaseMap.Lower omitUnchangedText();
+ }
+
+ public static final class CaseMap.Title extends android.icu.text.CaseMap {
+ method public <A extends java.lang.Appendable> A apply(java.util.Locale, android.icu.text.BreakIterator, java.lang.CharSequence, A, android.icu.text.Edits);
+ method public android.icu.text.CaseMap.Title noBreakAdjustment();
+ method public android.icu.text.CaseMap.Title noLowercase();
+ method public android.icu.text.CaseMap.Title omitUnchangedText();
+ }
+
+ public static final class CaseMap.Upper extends android.icu.text.CaseMap {
+ method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+ method public android.icu.text.CaseMap.Upper omitUnchangedText();
+ }
+
public final class CollationElementIterator {
method public int getMaxExpansion(int);
method public int getOffset();
@@ -19197,6 +19342,30 @@
enum_constant public static final android.icu.text.DisplayContext.Type SUBSTITUTE_HANDLING;
}
+ public final class Edits {
+ ctor public Edits();
+ method public void addReplace(int, int);
+ method public void addUnchanged(int);
+ method public android.icu.text.Edits.Iterator getCoarseChangesIterator();
+ method public android.icu.text.Edits.Iterator getCoarseIterator();
+ method public android.icu.text.Edits.Iterator getFineChangesIterator();
+ method public android.icu.text.Edits.Iterator getFineIterator();
+ method public boolean hasChanges();
+ method public int lengthDelta();
+ method public void reset();
+ }
+
+ public static final class Edits.Iterator {
+ method public int destinationIndex();
+ method public boolean findSourceIndex(int);
+ method public boolean hasChange();
+ method public int newLength();
+ method public boolean next();
+ method public int oldLength();
+ method public int replacementIndex();
+ method public int sourceIndex();
+ }
+
public abstract class IDNA {
method public static android.icu.text.IDNA getUTS46Instance(int);
method public abstract java.lang.StringBuilder labelToASCII(java.lang.CharSequence, java.lang.StringBuilder, android.icu.text.IDNA.Info);
@@ -26927,6 +27096,7 @@
method public android.net.Network[] getAllNetworks();
method public deprecated boolean getBackgroundDataSetting();
method public android.net.Network getBoundNetworkForProcess();
+ method public int getConnectionOwnerUid(int, java.net.InetSocketAddress, java.net.InetSocketAddress);
method public android.net.ProxyInfo getDefaultProxy();
method public android.net.LinkProperties getLinkProperties(android.net.Network);
method public int getMultipathPreference(android.net.Network);
@@ -33053,6 +33223,7 @@
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final deprecated boolean supportsProcesses();
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
+ field public static final int INVALID_UID = -1; // 0xffffffff
field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
@@ -40865,6 +41036,7 @@
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
@@ -40902,8 +41074,9 @@
public abstract class CallRedirectionService extends android.app.Service {
ctor public CallRedirectionService();
method public final void cancelCall();
- method public android.os.IBinder onBind(android.content.Intent);
+ method public final android.os.IBinder onBind(android.content.Intent);
method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public final boolean onUnbind(android.content.Intent);
method public final void placeCallUnmodified();
method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
@@ -41519,6 +41692,7 @@
field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+ field public static final java.lang.String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
@@ -41816,6 +41990,7 @@
field public static final deprecated java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+ field public static final java.lang.String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
@@ -42077,6 +42252,13 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
+ public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsGroupCallSessionCallback);
+ method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback);
+ method public android.telephony.mbms.GroupCall startGroupCall(java.util.concurrent.Executor, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ }
+
public class MbmsStreamingSession implements java.lang.AutoCloseable {
method public void close();
method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsStreamingSessionCallback);
@@ -42085,7 +42267,7 @@
method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
}
- public class NeighboringCellInfo implements android.os.Parcelable {
+ public deprecated class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
ctor public NeighboringCellInfo(int, java.lang.String, int);
@@ -42454,9 +42636,13 @@
method public static int getDefaultSmsSubscriptionId();
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
+ method public static int getSlotIndex(int);
method public static int[] getSubscriptionIds(int);
+ method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+ method public boolean isActiveSubscriptionId(int);
method public boolean isNetworkRoaming(int);
+ method public static boolean isUsableSubscriptionId(int);
method public static boolean isValidSubscriptionId(int);
method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
@@ -42470,7 +42656,9 @@
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+ field public static final int INVALID_SIM_SLOT_INDEX = -1; // 0xffffffff
field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
@@ -42541,7 +42729,6 @@
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public java.lang.String getNai();
- method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public java.lang.String getNetworkCountryIso();
method public java.lang.String getNetworkOperator();
method public java.lang.String getNetworkOperatorName();
@@ -42843,6 +43030,37 @@
}
+package android.telephony.emergency {
+
+ public final class EmergencyNumber implements java.lang.Comparable android.os.Parcelable {
+ method public int compareTo(android.telephony.emergency.EmergencyNumber);
+ method public int describeContents();
+ method public java.lang.String getCountryIso();
+ method public int getEmergencyNumberSourceBitmask();
+ method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
+ method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
+ method public int getEmergencyServiceCategoryBitmask();
+ method public java.lang.String getNumber();
+ method public boolean isFromSources(int);
+ method public boolean isInEmergencyServiceCategories(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR;
+ field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8
+ field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4
+ field public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 1; // 0x1
+ field public static final int EMERGENCY_NUMBER_SOURCE_SIM = 2; // 0x2
+ field public static final int EMERGENCY_SERVICE_CATEGORY_AIEC = 64; // 0x40
+ field public static final int EMERGENCY_SERVICE_CATEGORY_AMBULANCE = 2; // 0x2
+ field public static final int EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = 4; // 0x4
+ field public static final int EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = 8; // 0x8
+ field public static final int EMERGENCY_SERVICE_CATEGORY_MIEC = 32; // 0x20
+ field public static final int EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = 16; // 0x10
+ field public static final int EMERGENCY_SERVICE_CATEGORY_POLICE = 1; // 0x1
+ field public static final int EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = 0; // 0x0
+ }
+
+}
+
package android.telephony.euicc {
public final class DownloadableSubscription implements android.os.Parcelable {
@@ -43022,6 +43240,29 @@
field public static final android.os.Parcelable.Creator<android.telephony.mbms.FileServiceInfo> CREATOR;
}
+ public class GroupCall implements java.lang.AutoCloseable {
+ method public void close();
+ method public long getTmgi();
+ method public void updateGroupCall(int[], int[]);
+ field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
+ field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
+ field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
+ field public static final int REASON_NONE = 0; // 0x0
+ field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
+ field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+ field public static final int STATE_STALLED = 3; // 0x3
+ field public static final int STATE_STARTED = 2; // 0x2
+ field public static final int STATE_STOPPED = 1; // 0x1
+ }
+
+ public class GroupCallCallback {
+ ctor public GroupCallCallback();
+ method public void onBroadcastSignalStrengthUpdated(int);
+ method public void onError(int, java.lang.String);
+ method public void onGroupCallStateChanged(int, int);
+ field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
+ }
+
public class MbmsDownloadReceiver extends android.content.BroadcastReceiver {
ctor public MbmsDownloadReceiver();
method public void onReceive(android.content.Context, android.content.Intent);
@@ -43070,6 +43311,14 @@
field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
}
+ public class MbmsGroupCallSessionCallback {
+ ctor public MbmsGroupCallSessionCallback();
+ method public void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
+ method public void onError(int, java.lang.String);
+ method public void onMiddlewareReady();
+ method public void onServiceInterfaceAvailable(java.lang.String, int);
+ }
+
public class MbmsStreamingSessionCallback {
ctor public MbmsStreamingSessionCallback();
method public void onError(int, java.lang.String);
@@ -54661,6 +54910,7 @@
public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader);
ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
+ ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader, boolean);
}
public class DexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/removed.txt b/api/removed.txt
index f35348e..fba5187 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -540,6 +540,7 @@
}
public class TelephonyManager {
+ method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 1df9a46..d6002dd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -120,6 +120,7 @@
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+ field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -3074,6 +3075,7 @@
public class ConnectivityManager {
method public java.lang.String getCaptivePortalServerUrl();
method public boolean isTetheringSupported();
+ method public void setAirplaneMode(boolean);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method public void stopTethering(int);
@@ -5048,6 +5050,7 @@
method public deprecated android.content.ComponentName getDefaultPhoneApp();
method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
+ method public boolean isInEmergencyCall();
method public boolean isRinging();
method public boolean isTtySupported();
field public static final java.lang.String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
@@ -5074,6 +5077,10 @@
field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
}
+ public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+ field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_ACTION = "android.telephony.action.EmbmsGroupCall";
+ }
+
public class MbmsStreamingSession implements java.lang.AutoCloseable {
field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
@@ -5090,6 +5097,7 @@
method public int getRejectCause();
method public int getTransportType();
method public boolean isEmergencyEnabled();
+ method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
field public static final int DOMAIN_CS = 1; // 0x1
@@ -5132,10 +5140,18 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public class PhoneStateListener {
+ method public void onRadioPowerStateChanged(int);
+ field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 4194304; // 0x400000
+ }
+
public class ServiceState implements android.os.Parcelable {
+ method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
- method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int);
- method public android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int);
+ method public deprecated java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int);
+ method public deprecated android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int);
+ method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForDomain(int);
+ method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(int);
}
public final class SmsManager {
@@ -5174,6 +5190,8 @@
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+ field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
}
public final class SubscriptionPlan implements android.os.Parcelable {
@@ -5230,7 +5248,6 @@
}
public class TelephonyManager {
- method public deprecated void answerRingingCall();
method public deprecated void call(java.lang.String, java.lang.String);
method public int checkCarrierPrivilegesForPackage(java.lang.String);
method public int checkCarrierPrivilegesForPackageAnyPhone(java.lang.String);
@@ -5238,7 +5255,7 @@
method public boolean disableDataConnectivity();
method public boolean enableDataConnectivity();
method public void enableVideoCalling(boolean);
- method public deprecated boolean endCall();
+ method public java.lang.String getAidForAppType(int);
method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -5253,6 +5270,9 @@
method public deprecated boolean getDataEnabled();
method public deprecated boolean getDataEnabled(int);
method public boolean getEmergencyCallbackMode();
+ method public java.lang.String getIsimDomain();
+ method public int getPreferredNetworkType(int);
+ method public int getRadioPowerState();
method public int getSimApplicationState();
method public int getSimCardState();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5262,10 +5282,7 @@
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
method public boolean isDataConnectivityPossible();
- method public deprecated boolean isIdle();
- method public deprecated boolean isOffhook();
method public deprecated boolean isRadioOn();
- method public deprecated boolean isRinging();
method public boolean isVideoCallingEnabled();
method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
@@ -5279,7 +5296,6 @@
method public void setSimPowerStateForSlot(int, int);
method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
method public void setVoiceActivationState(int);
- method public deprecated void silenceRinger();
method public boolean supplyPin(java.lang.String);
method public int[] supplyPinReportResult(java.lang.String);
method public boolean supplyPuk(java.lang.String, java.lang.String);
@@ -5297,6 +5313,32 @@
field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+ field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4
+ field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5
+ field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6
+ field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7
+ field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1
+ field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3
+ field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8
+ field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa
+ field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9
+ field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb
+ field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14
+ field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13
+ field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc
+ field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15
+ field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10
+ field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12
+ field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd
+ field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
+ field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
+ field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
+ field public static final int RADIO_POWER_OFF = 0; // 0x0
+ field public static final int RADIO_POWER_ON = 1; // 0x1
+ field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
@@ -5363,17 +5405,12 @@
}
public final class DataProfile implements android.os.Parcelable {
- ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
- ctor public DataProfile(android.os.Parcel);
- method public int describeContents();
method public java.lang.String getApn();
method public int getAuthType();
method public int getBearerBitmap();
method public int getMaxConns();
method public int getMaxConnsTime();
method public int getMtu();
- method public java.lang.String getMvnoMatchData();
- method public java.lang.String getMvnoType();
method public java.lang.String getPassword();
method public int getProfileId();
method public java.lang.String getProtocol();
@@ -5383,9 +5420,8 @@
method public java.lang.String getUserName();
method public int getWaitTime();
method public boolean isEnabled();
- method public boolean isModemCognitive();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+ method public boolean isPersistent();
+ method public boolean isPreferred();
field public static final int TYPE_3GPP = 1; // 0x1
field public static final int TYPE_3GPP2 = 2; // 0x2
field public static final int TYPE_COMMON = 0; // 0x0
@@ -5632,6 +5668,7 @@
field public static final java.lang.String EXTRA_CODEC = "Codec";
field public static final java.lang.String EXTRA_DIALSTRING = "dialstring";
field public static final java.lang.String EXTRA_DISPLAY_TEXT = "DisplayText";
+ field public static final java.lang.String EXTRA_EMERGENCY_CALL = "e_call";
field public static final java.lang.String EXTRA_IS_CALL_PULL = "CallPull";
field public static final java.lang.String EXTRA_OI = "oi";
field public static final java.lang.String EXTRA_OIR = "oir";
@@ -6375,6 +6412,17 @@
method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
}
+ public class MbmsGroupCallServiceBase extends android.app.Service {
+ ctor public MbmsGroupCallServiceBase();
+ method public void dispose(int) throws android.os.RemoteException;
+ method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+ method public void onAppCallbackDied(int, int);
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ method public void stopGroupCall(int, long);
+ method public void updateGroupCall(int, long, int[], int[]);
+ }
+
public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 961026b..72b60e2 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -143,3 +143,16 @@
}
+package android.telephony {
+
+ public class TelephonyManager {
+ method public deprecated void answerRingingCall();
+ method public deprecated boolean endCall();
+ method public deprecated boolean isIdle();
+ method public deprecated boolean isOffhook();
+ method public deprecated boolean isRinging();
+ method public deprecated void silenceRinger();
+ }
+
+}
+
diff --git a/api/test-current.txt b/api/test-current.txt
index 634293a..a7bb467 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -966,6 +966,10 @@
field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
}
+ public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+ field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA = "mbms-group-call-service-override";
+ }
+
public class MbmsStreamingSession implements java.lang.AutoCloseable {
field public static final java.lang.String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
@@ -1035,6 +1039,17 @@
method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
}
+ public class MbmsGroupCallServiceBase extends android.app.Service {
+ ctor public MbmsGroupCallServiceBase();
+ method public void dispose(int) throws android.os.RemoteException;
+ method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+ method public void onAppCallbackDied(int, int);
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ method public void stopGroupCall(int, long);
+ method public void updateGroupCall(int, long, int[], int[]);
+ }
+
public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 4bbe042..72a4103 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -425,7 +425,19 @@
WorkerThreadSection::~WorkerThreadSection() {}
+void sigpipe_handler(int signum) {
+ if (signum == SIGPIPE) {
+ ALOGE("Wrote to a broken pipe\n");
+ } else {
+ ALOGE("Received unexpected signal: %d\n", signum);
+ }
+}
+
static void* worker_thread_func(void* cookie) {
+ // Don't crash the service if we write to a closed pipe (which can happen if
+ // dumping times out).
+ signal(SIGPIPE, sigpipe_handler);
+
WorkerThreadData* data = (WorkerThreadData*)cookie;
status_t err = data->section->BlockingCall(data->pipe.writeFd().get());
@@ -506,6 +518,7 @@
}
}
}
+
write_section_stats(requests->sectionStats(this->id), buffer);
if (timedOut || buffer.timedOut()) {
ALOGW("WorkerThreadSection '%s' timed out", this->name.string());
@@ -813,7 +826,10 @@
}
}
gLastLogsRetrieved[mLogID] = lastTimestamp;
- proto.flush(pipeWriteFd);
+ if (!proto.flush(pipeWriteFd) && errno == EPIPE) {
+ ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+ return EPIPE;
+ }
return NO_ERROR;
}
@@ -915,7 +931,7 @@
break;
}
if (cStatus != NO_ERROR) {
- ALOGE("TombstoneSection '%s' child had an issue: %s\n", this->name.string(), strerror(-cStatus));
+ ALOGE("[%s] child had an issue: %s\n", this->name.string(), strerror(-cStatus));
}
auto dump = std::make_unique<char[]>(buffer.size());
@@ -934,7 +950,13 @@
dumpPipe.readFd().reset();
}
- proto.flush(pipeWriteFd);
+ if (!proto.flush(pipeWriteFd) && errno == EPIPE) {
+ ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+ if (err != NO_ERROR) {
+ return EPIPE;
+ }
+ }
+
return err;
}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index a031a15..2f89370 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -173,7 +173,7 @@
*/
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 ab9c7e8..e12b665 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -120,6 +120,8 @@
AppCrashOccurred app_crash_occurred = 78;
ANROccurred anr_occurred = 79;
WTFOccurred wtf_occurred = 80;
+ PhoneServiceStateChanged phone_service_state_changed = 94;
+ PhoneStateChanged phone_state_changed = 95;
LowMemReported low_mem_reported = 81;
@@ -152,8 +154,9 @@
Temperature temperature = 10021;
}
- // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
- // 100,000 are reserved for non-AOSP (e.g. OEMs) to use.
+ // DO NOT USE field numbers above 100,000 in AOSP.
+ // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
+ // Field numbers 200,000 and above are reserved for future use; do not use them at all.
}
/**
@@ -272,9 +275,9 @@
* Logs reporting of a ble scan finding results.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
*/
-// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+// TODO: Consider also tracking per-scanner-id.
message BleScanResultReceived {
repeated AttributionNode attribution_node = 1;
@@ -1136,6 +1139,33 @@
optional android.telephony.SignalStrengthEnum signal_strength = 1;
}
+
+/**
+ * Logs when the phone state, sim state or signal strength changes
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PhoneServiceStateChanged {
+ optional android.telephony.ServiceStateEnum state = 1;
+ optional android.telephony.SimStateEnum sim_state = 2;
+ optional android.telephony.SignalStrengthEnum signal_strength = 3;
+}
+
+/**
+ * Logs when the phone becomes on or off.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/TelephonyRegistry.java
+ */
+message PhoneStateChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
/**
* Logs that a setting was updated.
* Logged from:
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
index c501c9f..543a748 100644
--- a/cmds/statsd/src/hash.cpp
+++ b/cmds/statsd/src/hash.cpp
@@ -16,6 +16,10 @@
#include "hash.h"
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
namespace android {
namespace os {
namespace statsd {
@@ -67,8 +71,10 @@
switch (n) {
case 3:
h ^= ByteAs32(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs32(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs32(data[0]);
h *= m;
@@ -104,16 +110,22 @@
switch (n) {
case 7:
h ^= ByteAs64(data[6]) << 48;
+ FALLTHROUGH_INTENDED;
case 6:
h ^= ByteAs64(data[5]) << 40;
+ FALLTHROUGH_INTENDED;
case 5:
h ^= ByteAs64(data[4]) << 32;
+ FALLTHROUGH_INTENDED;
case 4:
h ^= ByteAs64(data[3]) << 24;
+ FALLTHROUGH_INTENDED;
case 3:
h ^= ByteAs64(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs64(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs64(data[0]);
h *= m;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index fff909c..73ac968 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -489,6 +489,10 @@
{"AID_RESERVED_DISK", 1065},
{"AID_STATSD", 1066},
{"AID_INCIDENTD", 1067},
+ {"AID_SECURE_ELEMENT", 1068},
+ {"AID_LMKD", 1069},
+ {"AID_LLKD", 1070},
+ {"AID_IORAPD", 1071},
{"AID_SHELL", 2000},
{"AID_CACHE", 2001},
{"AID_DIAG", 2002}};
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 3567605..9857cd0 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -11074,6 +11074,7 @@
HPLjava/lang/Long;->valueOf(Ljava/lang/String;I)Ljava/lang/Long;
HPLjava/lang/Math;->addExact(JJ)J
HPLjava/lang/Math;->scalb(FI)F
+HPLjava/lang/Object;->wait()V
HPLjava/lang/StackTraceElement;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
HPLjava/lang/String;->copyValueOf([C)Ljava/lang/String;
HPLjava/lang/String;->join(Ljava/lang/CharSequence;[Ljava/lang/CharSequence;)Ljava/lang/String;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index d520b28..f0bc3d6 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -573,7 +573,6 @@
Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->reportInetCondition(II)V
-Landroid/net/IConnectivityManager;->setAirplaneMode(Z)V
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
@@ -2147,27 +2146,20 @@
Lcom/android/internal/telephony/ISub;->getDefaultSubId()I
Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_answerRingingCall:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
-Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V
Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V
Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V
Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z
Lcom/android/internal/telephony/ITelephony;->disableLocationUpdates()V
Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z
Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V
-Lcom/android/internal/telephony/ITelephony;->endCall()Z
-Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z
Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I
Lcom/android/internal/telephony/ITelephony;->getCallState()I
Lcom/android/internal/telephony/ITelephony;->getDataActivity()I
@@ -2179,12 +2171,8 @@
Lcom/android/internal/telephony/ITelephony;->hasIccCard()Z
Lcom/android/internal/telephony/ITelephony;->iccCloseLogicalChannel(II)Z
Lcom/android/internal/telephony/ITelephony;->iccTransmitApduLogicalChannel(IIIIIIILjava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isIdleForSubscriber(ILjava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->isRadioOnForSubscriber(ILjava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isRinging(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z
-Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
Lcom/android/internal/telephony/ITelephony;->supplyPin(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->toggleRadioOnOff()V
Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V
@@ -2205,6 +2193,7 @@
Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
+Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String;
Lcom/android/internal/view/BaseIWindow;-><init>()V
@@ -2293,17 +2282,12 @@
Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V
Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V
Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostname()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostnameOrIP()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getSoWriteTimeout()I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket;
Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V
Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
+Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2325,6 +2309,108 @@
Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List;
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
+Lcom/google/android/mms/MmsException;-><init>()V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
+Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
+Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
+Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
+Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
+Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
+Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
+Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
+Lcom/google/android/mms/pdu/PduBody;-><init>()V
+Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
+Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
+Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
+Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
+Lcom/google/android/mms/pdu/PduComposer;->make()[B
+Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPart;-><init>()V
+Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPart;->getCharset()I
+Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
+Lcom/google/android/mms/pdu/PduPart;->getData()[B
+Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
+Lcom/google/android/mms/pdu/PduPart;->getName()[B
+Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
+Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
+Lcom/google/android/mms/pdu/PduPart;->setData([B)V
+Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
+Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
+Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
+Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
+Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
+Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
+Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
+Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
+Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;-><init>()V
+Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
+Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
+Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
+Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
+Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
+Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
+Lcom/google/android/mms/util/PduCache;->purgeAll()V
+Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
Ldalvik/system/BaseDexClassLoader;-><init>(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/ClassLoader;Z)V
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V
@@ -2628,6 +2714,7 @@
Ljava/net/SocketException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
Ljava/net/SocketImpl;->serverSocket:Ljava/net/ServerSocket;
Ljava/net/SocketImpl;->socket:Ljava/net/Socket;
+Ljava/net/SocksSocketImpl;-><init>()V
Ljava/net/URI;->fragment:Ljava/lang/String;
Ljava/net/URI;->host:Ljava/lang/String;
Ljava/net/URI;->port:I
@@ -2773,15 +2860,6 @@
Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale;
-Llibcore/io/Memory;->peekByte(J)B
-Llibcore/io/Memory;->peekByteArray(J[BII)V
-Llibcore/io/Memory;->peekInt(JZ)I
-Llibcore/io/Memory;->peekLong(JZ)J
-Llibcore/io/Memory;->pokeByte(JB)V
-Llibcore/io/Memory;->pokeByteArray(J[BII)V
-Llibcore/io/Memory;->pokeInt(JIZ)V
-Llibcore/io/Memory;->pokeLong(JJZ)V
-Llibcore/io/Streams;->copy(Ljava/io/InputStream;Ljava/io/OutputStream;)I
Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap;
Llibcore/util/ZoneInfo;->mTransitions:[J
Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
diff --git a/config/hiddenapi-max-sdk-p-blacklist.txt b/config/hiddenapi-max-sdk-p-blacklist.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/hiddenapi-max-sdk-p-blacklist.txt
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f..d93befd 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2381,7 +2381,6 @@
android.os.-$$Lambda$StrictMode$yZJXPvy2veRNA-xL_SWdXzX_OLg
android.os.-$$Lambda$Trace$2zLZ-Lc2kAXsVjw_nLYeNhqmGq0
android.os.AsyncResult
-android.os.AsyncTask
android.os.AsyncTask$1
android.os.AsyncTask$2
android.os.AsyncTask$3
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index 8b8d640..eca3bf3 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,4 +1,5 @@
android.net.ConnectivityThread$Singleton
+android.os.AsyncTask
android.os.FileObserver
android.widget.Magnifier
sun.nio.fs.UnixChannelFactory
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4c655b5..654bfaf 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -81,7 +81,8 @@
* {@link #getBondedDevices()}; start device discovery with
* {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
* listen for incoming RFComm connection requests with {@link
- * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for
+ * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
+ * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for
* Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
* </p>
* <p>This class is thread safe.</p>
@@ -2967,7 +2968,7 @@
/**
* Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
* assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
- * for incoming connections.
+ * for incoming connections. The supported Bluetooth transport is LE only.
* <p>A remote device connecting to this socket will be authenticated and communication on this
* socket will be encrypted.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
@@ -2977,21 +2978,16 @@
* closed, Bluetooth is turned off, or the application exits unexpectedly.
* <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
* defined and performed by the application.
- * <p>Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server
+ * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server
* socket from another Android device that is given the PSM value.
*
- * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
* @return an L2CAP CoC BluetoothServerSocket
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or unable to start this CoC
- * @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothServerSocket listenUsingL2capCoc(int transport)
+ public BluetoothServerSocket listenUsingL2capChannel()
throws IOException {
- if (transport != BluetoothDevice.TRANSPORT_LE) {
- throw new IllegalArgumentException("Unsupported transport: " + transport);
- }
BluetoothServerSocket socket =
new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
@@ -3005,7 +3001,7 @@
throw new IOException("Error: Unable to assign PSM value");
}
if (DBG) {
- Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to "
+ Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to "
+ assignedPsm);
}
socket.setChannel(assignedPsm);
@@ -3014,10 +3010,23 @@
}
/**
+ * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+ * API name, listenUsingL2capChannel.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public BluetoothServerSocket listenUsingL2capCoc(int transport)
+ throws IOException {
+ Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel");
+ return listenUsingL2capChannel();
+ }
+
+ /**
* Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
- * assign a dynamic PSM value. This socket can be used to listen for incoming connections.
+ * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
+ * supported Bluetooth transport is LE only.
* <p>The link key is not required to be authenticated, i.e the communication may be vulnerable
- * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and
+ * to man-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and
* authenticated communication channel is desired.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
* {@link BluetoothServerSocket}.
@@ -3027,21 +3036,16 @@
* unexpectedly.
* <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
* defined and performed by the application.
- * <p>Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this
- * server socket from another Android device that is given the PSM value.
+ * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server
+ * socket from another Android device that is given the PSM value.
*
- * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
* @return an L2CAP CoC BluetoothServerSocket
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or unable to start this CoC
- * @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
+ public BluetoothServerSocket listenUsingInsecureL2capChannel()
throws IOException {
- if (transport != BluetoothDevice.TRANSPORT_LE) {
- throw new IllegalArgumentException("Unsupported transport: " + transport);
- }
BluetoothServerSocket socket =
new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
@@ -3055,11 +3059,24 @@
throw new IOException("Error: Unable to assign PSM value");
}
if (DBG) {
- Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to "
+ Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to "
+ assignedPsm);
}
socket.setChannel(assignedPsm);
return socket;
}
+
+ /**
+ * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+ * API name, listenUsingInsecureL2capChannel.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
+ throws IOException {
+ Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, "
+ + "listenUsingInsecureL2capChannel");
+ return listenUsingInsecureL2capChannel();
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 818a749..d9e6fa2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -107,20 +107,6 @@
"android.bluetooth.device.action.FOUND";
/**
- * Broadcast Action: Remote device disappeared.
- * <p>Sent when a remote device that was found in the last discovery is not
- * found in the current discovery.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String ACTION_DISAPPEARED =
- "android.bluetooth.device.action.DISAPPEARED";
-
- /**
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
@@ -1963,8 +1949,8 @@
/**
* Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
* be used to start a secure outgoing connection to the remote device with the same dynamic
- * protocol/service multiplexer (PSM) value.
- * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capCoc(int)} for
+ * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
+ * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
* peer-peer Bluetooth applications.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
* <p>Application using this API is responsible for obtaining PSM value from remote device.
@@ -1975,59 +1961,71 @@
* secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int,
* int)}.
*
- * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
* @param psm dynamic PSM value from remote device
* @return a CoC #BluetoothSocket ready for an outgoing connection
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
- * @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
+ public BluetoothSocket createL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
- Log.e(TAG, "createL2capCocSocket: Bluetooth is not enabled");
+ Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
throw new IOException();
}
- if (transport != BluetoothDevice.TRANSPORT_LE) {
- throw new IllegalArgumentException("Unsupported transport: " + transport);
- }
- if (DBG) Log.d(TAG, "createL2capCocSocket: transport=" + transport + ", psm=" + psm);
+ if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
null);
}
/**
+ * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+ * API name, createL2capChannel.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
+ Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel");
+ return createL2capChannel(psm);
+ }
+
+ /**
* Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
* be used to start a secure outgoing connection to the remote device with the same dynamic
- * protocol/service multiplexer (PSM) value.
- * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingInsecureL2capCoc(int)}
- * for peer-peer Bluetooth applications.
+ * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
+ * <p>This is designed to be used with {@link
+ * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
* <p>Application using this API is responsible for obtaining PSM value from remote device.
* <p> The communication channel may not have an authenticated link key, i.e. it may be subject
- * to man-in-the-middle attacks. Use {@link #createL2capCocSocket(int, int)} if an encrypted and
+ * to man-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
* authenticated communication channel is possible.
*
- * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
* @param psm dynamic PSM value from remote device
* @return a CoC #BluetoothSocket ready for an outgoing connection
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
+ if (!isBluetoothEnabled()) {
+ Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
+ throw new IOException();
+ }
+ if (DBG) {
+ Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
+ }
+ return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
+ null);
+ }
+
+ /**
+ * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+ * API name, createInsecureL2capChannel.
* @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled");
- throw new IOException();
- }
- if (transport != BluetoothDevice.TRANSPORT_LE) {
- throw new IllegalArgumentException("Unsupported transport: " + transport);
- }
- if (DBG) {
- Log.d(TAG, "createInsecureL2capCocSocket: transport=" + transport + ", psm=" + psm);
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
- null);
+ Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
+ return createInsecureL2capChannel(psm);
}
}
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 183be5f..559a59b 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -73,6 +73,8 @@
/** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2;
+ private static final int UPLOADING_FEATURE_BITMASK = 0x08;
+
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
@@ -395,6 +397,23 @@
return false;
}
+ /**
+ * Returns the "Uploading" feature bit value from the SDP record's
+ * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114).
+ * @param device The Bluetooth device to get this value for.
+ * @return Returns true if the Uploading bit value in SDP record's
+ * MapSupportedFeatures field is set. False is returned otherwise.
+ */
+ public boolean isUploadingSupported(BluetoothDevice device) {
+ try {
+ return (mService != null && isEnabled() && isValidDevice(device))
+ && ((mService.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ return false;
+ }
+
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index ba4b5a5..5fc344a 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,12 +203,11 @@
/**
* Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
* Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
- * {#link BluetoothAdapter.listenUsingL2capCoc(int)} or {#link
- * BluetoothAdapter.listenUsingInsecureL2capCoc(int)}. The returned value is undefined if this
+ * {#link BluetoothAdapter.listenUsingL2capChannel()} or {#link
+ * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
* method is called on non-L2CAP server sockets.
*
* @return the assigned PSM or LE_PSM value depending on transport
- * @hide
*/
public int getPsm() {
return mChannel;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 780f896..3a1e2f5 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -667,6 +667,10 @@
* @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
*/
public int getConnectionType() {
+ if (mType == TYPE_L2CAP_LE) {
+ // Treat the LE CoC to be the same type as L2CAP.
+ return TYPE_L2CAP;
+ }
return mType;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0fc55b4..2b60770 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3946,6 +3946,12 @@
public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
/**
+ * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state.
+ * @hide
+ */
+ public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE";
+
+ /**
* The name of the extra used to define the text to be processed, as a
* CharSequence. Note that this may be a styled CharSequence, so you must use
* {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it.
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 212e132..7aa223c 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -124,7 +124,7 @@
*
* <p><strong>Data Authority</strong> matches if any of the given values match
* the Intent's data authority <em>and</em> one of the data schemes in the filter
- * has matched the Intent, <em>or</em> no authories were supplied in the filter.
+ * has matched the Intent, <em>or</em> no authorities were supplied in the filter.
* The Intent authority is determined by calling
* {@link Intent#getData} and {@link android.net.Uri#getAuthority} on that URI.
* <em>Note that authority matching here is <b>case sensitive</b>, unlike
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
new file mode 100644
index 0000000..69cc94f
--- /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 a16f81b..03eefed 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -53,6 +53,8 @@
"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/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5cbd185..35db667 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5132,6 +5132,7 @@
* @param packageName The name of the package to query
* @throws IllegalArgumentException if the given package name is not installed
*/
+ @Nullable
public abstract String getInstallerPackageName(String packageName);
/**
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 83e8663..387d29e8 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,6 +22,10 @@
*/
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/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index caa99d5..12c2149 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2082,7 +2082,7 @@
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
diff --git a/core/java/android/net/ConnectionInfo.aidl b/core/java/android/net/ConnectionInfo.aidl
new file mode 100644
index 0000000..07faf8b
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.net;
+
+parcelable ConnectionInfo;
diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java
new file mode 100644
index 0000000..58d0e05
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.java
@@ -0,0 +1,83 @@
+/*
+ * 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Describe a network connection including local and remote address/port of a connection and the
+ * transport protocol.
+ *
+ * @hide
+ */
+public final class ConnectionInfo implements Parcelable {
+ public final int protocol;
+ public final InetSocketAddress local;
+ public final InetSocketAddress remote;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) {
+ this.protocol = protocol;
+ this.local = local;
+ this.remote = remote;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(protocol);
+ out.writeByteArray(local.getAddress().getAddress());
+ out.writeInt(local.getPort());
+ out.writeByteArray(remote.getAddress().getAddress());
+ out.writeInt(remote.getPort());
+ }
+
+ public static final Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
+ public ConnectionInfo createFromParcel(Parcel in) {
+ int protocol = in.readInt();
+ InetAddress localAddress;
+ try {
+ localAddress = InetAddress.getByAddress(in.createByteArray());
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid InetAddress");
+ }
+ int localPort = in.readInt();
+ InetAddress remoteAddress;
+ try {
+ remoteAddress = InetAddress.getByAddress(in.createByteArray());
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid InetAddress");
+ }
+ int remotePort = in.readInt();
+ InetSocketAddress local = new InetSocketAddress(localAddress, localPort);
+ InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort);
+ return new ConnectionInfo(protocol, local, remote);
+ }
+
+ public ConnectionInfo[] newArray(int size) {
+ return new ConnectionInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce18796..1fbfa40 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -26,7 +26,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -59,6 +58,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -83,6 +83,7 @@
@SystemService(Context.CONNECTIVITY_SERVICE)
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* A change in network connectivity has occurred. A default connection has either
@@ -2493,6 +2494,7 @@
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
+ printStackTrace();
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
@@ -2513,6 +2515,7 @@
*/
@Deprecated
public void reportBadNetwork(Network network) {
+ printStackTrace();
try {
// One of these will be ignored because it matches system's current state.
// The other will trigger the necessary reevaluation.
@@ -2535,6 +2538,7 @@
* Internet using {@code network} or {@code false} if not.
*/
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ printStackTrace();
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
@@ -2727,8 +2731,11 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
- @UnsupportedAppUsage
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK})
+ @SystemApi
public void setAirplaneMode(boolean enable) {
try {
mService.setAirplaneMode(enable);
@@ -3073,6 +3080,7 @@
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+ printStackTrace();
checkCallbackNotNull(callback);
Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
final NetworkRequest request;
@@ -3332,6 +3340,7 @@
* {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
@@ -3355,6 +3364,7 @@
* corresponding NetworkRequest you'd like to remove. Cannot be null.
*/
public void releaseNetworkRequest(PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.releasePendingNetworkRequest(operation);
@@ -3439,6 +3449,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(request.networkCapabilities, operation);
@@ -3520,6 +3531,7 @@
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ printStackTrace();
checkCallbackNotNull(networkCallback);
final List<NetworkRequest> reqs = new ArrayList<>();
// Find all requests associated to this callback and stop callback triggers immediately.
@@ -3800,8 +3812,9 @@
private void unsupportedStartingFrom(int version) {
if (Process.myUid() == Process.SYSTEM_UID) {
- // The getApplicationInfo() call we make below is not supported in system context, and
- // we want to allow the system to use these APIs anyway.
+ // The getApplicationInfo() call we make below is not supported in system context. Let
+ // the call through here, and rely on the fact that ConnectivityService will refuse to
+ // allow the system to use these APIs anyway.
return;
}
@@ -3818,11 +3831,6 @@
// functions by accessing ConnectivityService directly. However, it should be clear that doing
// so is unsupported and may break in the future. http://b/22728205
private void checkLegacyRoutingApiAccess() {
- if (mContext.checkCallingOrSelfPermission("com.android.permission.INJECT_OMADM_SETTINGS")
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
-
unsupportedStartingFrom(VERSION_CODES.M);
}
@@ -3930,4 +3938,41 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns the {@code uid} of the owner of a network connection.
+ *
+ * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and
+ * {@code IPPROTO_UDP} currently supported.
+ * @param local The local {@link InetSocketAddress} of a connection.
+ * @param remote The remote {@link InetSocketAddress} of a connection.
+ *
+ * @return {@code uid} if the connection is found and the app has permission to observe it
+ * (e.g., if it is associated with the calling VPN app's tunnel) or
+ * {@link android.os.Process#INVALID_UID} if the connection is not found.
+ */
+ public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote) {
+ ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
+ try {
+ return mService.getConnectionOwnerUid(connectionInfo);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void printStackTrace() {
+ if (DEBUG) {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 3; i < callStack.length; i++) {
+ final String stackTrace = callStack[i].toString();
+ if (stackTrace == null || stackTrace.contains("android.os")) {
+ break;
+ }
+ sb.append(" [").append(stackTrace).append("]");
+ }
+ Log.d(TAG, "StackLog:" + sb.toString());
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index ce95b60..e7d441d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.app.PendingIntent;
+import android.net.ConnectionInfo;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -182,4 +183,6 @@
String getCaptivePortalServerUrl();
byte[] getNetworkWatchlistConfigHash();
+
+ int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
}
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
new file mode 100644
index 0000000..53037b24
--- /dev/null
+++ b/core/java/android/os/DumpstateOptions.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Options passed to dumpstate service.
+ *
+ * @hide
+ */
+public final class DumpstateOptions implements Parcelable {
+ // If true the caller can get callbacks with per-section
+ // progress details.
+ private final boolean mGetSectionDetails;
+ // Name of the caller.
+ private final String mName;
+
+ public DumpstateOptions(Parcel in) {
+ mGetSectionDetails = in.readBoolean();
+ mName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mGetSectionDetails);
+ out.writeString(mName);
+ }
+
+ public static final Parcelable.Creator<DumpstateOptions> CREATOR =
+ new Parcelable.Creator<DumpstateOptions>() {
+ public DumpstateOptions createFromParcel(Parcel in) {
+ return new DumpstateOptions(in);
+ }
+
+ public DumpstateOptions[] newArray(int size) {
+ return new DumpstateOptions[size];
+ }
+ };
+}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 20ca19b..c9c4205 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -388,10 +388,10 @@
/**
* Setup a new physical network.
- * @param permission null if no permissions required to access this network. PERMISSION_NETWORK
- * or PERMISSION_SYSTEM to set respective permission.
+ * @param permission PERMISSION_NONE if no permissions required to access this network.
+ * PERMISSION_NETWORK or PERMISSION_SYSTEM to set respective permission.
*/
- void createPhysicalNetwork(int netId, String permission);
+ void createPhysicalNetwork(int netId, int permission);
/**
* Setup a new VPN.
@@ -420,10 +420,10 @@
/**
* Set permission for a network.
- * @param permission null to clear permissions. PERMISSION_NETWORK or PERMISSION_SYSTEM to set
- * permission.
+ * @param permission PERMISSION_NONE to clear permissions.
+ * PERMISSION_NETWORK or PERMISSION_SYSTEM to set permission.
*/
- void setNetworkPermission(int netId, String permission);
+ void setNetworkPermission(int netId, int permission);
void setPermission(String permission, in int[] uids);
void clearPermission(in int[] uids);
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index b303e10..c3f60a3 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -366,7 +366,7 @@
* the <em>target</em> {@link Handler} that is receiving this Message to
* dispatch it. If
* not set, the message will be dispatched to the receiving Handler's
- * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+ * {@link Handler#handleMessage(Message)}.
*/
public Runnable getCallback() {
return callback;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7ce7c92..d0cdf6e 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -40,6 +40,11 @@
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
/**
+ * An invalid UID value.
+ */
+ public static final int INVALID_UID = -1;
+
+ /**
* Defines the root UID.
* @hide
*/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 3e8e885..8492b0c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -36,16 +36,12 @@
import android.view.Display;
import android.view.WindowManager;
-import com.android.internal.logging.MetricsLogger;
-
import libcore.io.Streams;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
@@ -97,7 +93,7 @@
/** Used to communicate with recovery. See bootable/recovery/recovery.cpp. */
private static final File RECOVERY_DIR = new File("/cache/recovery");
private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
- private static final File LAST_INSTALL_FILE = new File(RECOVERY_DIR, "last_install");
+ private static final String LAST_INSTALL_PATH = "last_install";
private static final String LAST_PREFIX = "last_";
private static final String ACTION_EUICC_FACTORY_RESET =
"com.android.internal.action.EUICC_FACTORY_RESET";
@@ -935,116 +931,6 @@
throw new IOException("Reboot failed (no permissions?)");
}
- // Read last_install; then report time (in seconds) and I/O (in MiB) for
- // this update to tron.
- // Only report on the reboots immediately after an OTA update.
- private static void parseLastInstallLog(Context context) {
- try (BufferedReader in = new BufferedReader(new FileReader(LAST_INSTALL_FILE))) {
- String line = null;
- int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
- int timeTotal = -1;
- int uncryptTime = -1;
- int sourceVersion = -1;
- int temperatureStart = -1;
- int temperatureEnd = -1;
- int temperatureMax = -1;
- int errorCode = -1;
- int causeCode = -1;
-
- while ((line = in.readLine()) != null) {
- // Here is an example of lines in last_install:
- // ...
- // time_total: 101
- // bytes_written_vendor: 51074
- // bytes_stashed_vendor: 200
- int numIndex = line.indexOf(':');
- if (numIndex == -1 || numIndex + 1 >= line.length()) {
- continue;
- }
- String numString = line.substring(numIndex + 1).trim();
- long parsedNum;
- try {
- parsedNum = Long.parseLong(numString);
- } catch (NumberFormatException ignored) {
- Log.e(TAG, "Failed to parse numbers in " + line);
- continue;
- }
-
- final int MiB = 1024 * 1024;
- int scaled;
- try {
- if (line.startsWith("bytes")) {
- scaled = Math.toIntExact(parsedNum / MiB);
- } else {
- scaled = Math.toIntExact(parsedNum);
- }
- } catch (ArithmeticException ignored) {
- Log.e(TAG, "Number overflows in " + line);
- continue;
- }
-
- if (line.startsWith("time")) {
- timeTotal = scaled;
- } else if (line.startsWith("uncrypt_time")) {
- uncryptTime = scaled;
- } else if (line.startsWith("source_build")) {
- sourceVersion = scaled;
- } else if (line.startsWith("bytes_written")) {
- bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
- bytesWrittenInMiB + scaled;
- } else if (line.startsWith("bytes_stashed")) {
- bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
- bytesStashedInMiB + scaled;
- } else if (line.startsWith("temperature_start")) {
- temperatureStart = scaled;
- } else if (line.startsWith("temperature_end")) {
- temperatureEnd = scaled;
- } else if (line.startsWith("temperature_max")) {
- temperatureMax = scaled;
- } else if (line.startsWith("error")) {
- errorCode = scaled;
- } else if (line.startsWith("cause")) {
- causeCode = scaled;
- }
- }
-
- // Don't report data to tron if corresponding entry isn't found in last_install.
- if (timeTotal != -1) {
- MetricsLogger.histogram(context, "ota_time_total", timeTotal);
- }
- if (uncryptTime != -1) {
- MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
- }
- if (sourceVersion != -1) {
- MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
- }
- if (bytesWrittenInMiB != -1) {
- MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
- }
- if (bytesStashedInMiB != -1) {
- MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
- }
- if (temperatureStart != -1) {
- MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
- }
- if (temperatureEnd != -1) {
- MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
- }
- if (temperatureMax != -1) {
- MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
- }
- if (errorCode != -1) {
- MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
- }
- if (causeCode != -1) {
- MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
- }
-
- } catch (IOException e) {
- Log.e(TAG, "Failed to read lines in last_install", e);
- }
- }
-
/**
* Called after booting to process and remove recovery-related files.
* @return the log file from recovery, or null if none was found.
@@ -1062,9 +948,6 @@
Log.e(TAG, "Error reading recovery log", e);
}
- if (log != null) {
- parseLastInstallLog(context);
- }
// Only remove the OTA package if it's partially processed (uncrypt'd).
boolean reservePackage = BLOCK_MAP_FILE.exists();
@@ -1095,7 +978,8 @@
// GmsCore to avoid re-downloading everything again.
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
- if (names[i].startsWith(LAST_PREFIX)) continue;
+ // Do not remove the last_install file since the recovery-persist takes care of it.
+ if (names[i].startsWith(LAST_PREFIX) || names[i].equals(LAST_INSTALL_PATH)) continue;
if (reservePackage && names[i].equals(BLOCK_MAP_FILE.getName())) continue;
if (reservePackage && names[i].equals(UNCRYPT_PACKAGE_FILE.getName())) continue;
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 534ef8d..4b5a7b4 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -43,7 +43,7 @@
* A base class for {@link Preference} objects that are
* dialog-based. These preferences will, when clicked, open a dialog showing the
* actual preference controls.
- *
+ *
* @attr ref android.R.styleable#DialogPreference_dialogTitle
* @attr ref android.R.styleable#DialogPreference_dialogMessage
* @attr ref android.R.styleable#DialogPreference_dialogIcon
@@ -56,7 +56,7 @@
PreferenceManager.OnActivityDestroyListener {
@UnsupportedAppUsage
private AlertDialog.Builder mBuilder;
-
+
@UnsupportedAppUsage
private CharSequence mDialogTitle;
@UnsupportedAppUsage
@@ -77,6 +77,14 @@
@UnsupportedAppUsage
private int mWhichButtonClicked;
+ /** Dismiss the dialog on the UI thread, but not inline with handlers */
+ private final Runnable mDismissRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mDialog.dismiss();
+ }
+ };
+
public DialogPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -112,7 +120,7 @@
/**
* Sets the title of the dialog. This will be shown on subsequent dialogs.
- *
+ *
* @param dialogTitle The title.
*/
public void setDialogTitle(CharSequence dialogTitle) {
@@ -126,7 +134,7 @@
public void setDialogTitle(int dialogTitleResId) {
setDialogTitle(getContext().getString(dialogTitleResId));
}
-
+
/**
* Returns the title to be shown on subsequent dialogs.
* @return The title.
@@ -134,7 +142,7 @@
public CharSequence getDialogTitle() {
return mDialogTitle;
}
-
+
/**
* Sets the message of the dialog. This will be shown on subsequent dialogs.
* <p>
@@ -142,7 +150,7 @@
* list-based dialogs, for example. If setting a custom View on a dialog via
* {@link #setDialogLayoutResource(int)}, include a text View with ID
* {@link android.R.id#message} and it will be populated with this message.
- *
+ *
* @param dialogMessage The message.
*/
public void setDialogMessage(CharSequence dialogMessage) {
@@ -156,7 +164,7 @@
public void setDialogMessage(int dialogMessageResId) {
setDialogMessage(getContext().getString(dialogMessageResId));
}
-
+
/**
* Returns the message to be shown on subsequent dialogs.
* @return The message.
@@ -164,26 +172,26 @@
public CharSequence getDialogMessage() {
return mDialogMessage;
}
-
+
/**
* Sets the icon of the dialog. This will be shown on subsequent dialogs.
- *
+ *
* @param dialogIcon The icon, as a {@link Drawable}.
*/
public void setDialogIcon(Drawable dialogIcon) {
mDialogIcon = dialogIcon;
}
-
+
/**
* Sets the icon (resource ID) of the dialog. This will be shown on
* subsequent dialogs.
- *
+ *
* @param dialogIconRes The icon, as a resource ID.
*/
public void setDialogIcon(@DrawableRes int dialogIconRes) {
mDialogIcon = getContext().getDrawable(dialogIconRes);
}
-
+
/**
* Returns the icon to be shown on subsequent dialogs.
* @return The icon, as a {@link Drawable}.
@@ -191,11 +199,11 @@
public Drawable getDialogIcon() {
return mDialogIcon;
}
-
+
/**
* Sets the text of the positive button of the dialog. This will be shown on
* subsequent dialogs.
- *
+ *
* @param positiveButtonText The text of the positive button.
*/
public void setPositiveButtonText(CharSequence positiveButtonText) {
@@ -209,27 +217,27 @@
public void setPositiveButtonText(@StringRes int positiveButtonTextResId) {
setPositiveButtonText(getContext().getString(positiveButtonTextResId));
}
-
+
/**
* Returns the text of the positive button to be shown on subsequent
* dialogs.
- *
+ *
* @return The text of the positive button.
*/
public CharSequence getPositiveButtonText() {
return mPositiveButtonText;
}
-
+
/**
* Sets the text of the negative button of the dialog. This will be shown on
* subsequent dialogs.
- *
+ *
* @param negativeButtonText The text of the negative button.
*/
public void setNegativeButtonText(CharSequence negativeButtonText) {
mNegativeButtonText = negativeButtonText;
}
-
+
/**
* @see #setNegativeButtonText(CharSequence)
* @param negativeButtonTextResId The negative button text as a resource.
@@ -237,38 +245,38 @@
public void setNegativeButtonText(@StringRes int negativeButtonTextResId) {
setNegativeButtonText(getContext().getString(negativeButtonTextResId));
}
-
+
/**
* Returns the text of the negative button to be shown on subsequent
* dialogs.
- *
+ *
* @return The text of the negative button.
*/
public CharSequence getNegativeButtonText() {
return mNegativeButtonText;
}
-
+
/**
* Sets the layout resource that is inflated as the {@link View} to be shown
* as the content View of subsequent dialogs.
- *
+ *
* @param dialogLayoutResId The layout resource ID to be inflated.
* @see #setDialogMessage(CharSequence)
*/
public void setDialogLayoutResource(int dialogLayoutResId) {
mDialogLayoutResId = dialogLayoutResId;
}
-
+
/**
* Returns the layout resource that is used as the content View for
* subsequent dialogs.
- *
+ *
* @return The layout resource.
*/
public int getDialogLayoutResource() {
return mDialogLayoutResId;
}
-
+
/**
* Prepares the dialog builder to be shown when the preference is clicked.
* Use this to set custom properties on the dialog.
@@ -278,7 +286,7 @@
*/
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
}
-
+
@Override
protected void onClick() {
if (mDialog != null && mDialog.isShowing()) return;
@@ -290,14 +298,14 @@
* Shows the dialog associated with this Preference. This is normally initiated
* automatically on clicking on the preference. Call this method if you need to
* show the dialog on some other event.
- *
+ *
* @param state Optional instance state to restore on the dialog
*/
protected void showDialog(Bundle state) {
Context context = getContext();
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
-
+
mBuilder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle)
.setIcon(mDialogIcon)
@@ -311,11 +319,11 @@
} else {
mBuilder.setMessage(mDialogMessage);
}
-
+
onPrepareDialogBuilder(mBuilder);
-
+
getPreferenceManager().registerOnActivityDestroyListener(this);
-
+
// Create the dialog
final Dialog dialog = mDialog = mBuilder.create();
if (state != null) {
@@ -324,10 +332,29 @@
if (needInputMethod()) {
requestInputMethod(dialog);
}
+ dialog.setOnShowListener(new DialogInterface.OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ removeDismissCallbacks();
+ }
+ });
dialog.setOnDismissListener(this);
dialog.show();
}
+ void postDismiss() {
+ removeDismissCallbacks();
+ View decorView = mDialog.getWindow().getDecorView();
+ decorView.post(mDismissRunnable);
+ }
+
+ private void removeDismissCallbacks() {
+ if (mDialog != null && mDialog.getWindow() != null
+ && mDialog.getWindow().getDecorView() != null) {
+ mDialog.getWindow().getDecorView().removeCallbacks(mDismissRunnable);
+ }
+ }
+
/**
* Returns whether the preference needs to display a soft input method when the dialog
* is displayed. Default is false. Subclasses should override this method if they need
@@ -350,7 +377,7 @@
* Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is
* set.
- *
+ *
* @return The content View for the dialog.
* @see #setLayoutResource(int)
*/
@@ -358,48 +385,49 @@
if (mDialogLayoutResId == 0) {
return null;
}
-
+
LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext());
return inflater.inflate(mDialogLayoutResId, null);
}
-
+
/**
* Binds views in the content View of the dialog to data.
* <p>
* Make sure to call through to the superclass implementation.
- *
+ *
* @param view The content View of the dialog, if it is custom.
*/
@CallSuper
protected void onBindDialogView(View view) {
View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
-
+
if (dialogMessageView != null) {
final CharSequence message = getDialogMessage();
int newVisibility = View.GONE;
-
+
if (!TextUtils.isEmpty(message)) {
if (dialogMessageView instanceof TextView) {
((TextView) dialogMessageView).setText(message);
}
-
+
newVisibility = View.VISIBLE;
}
-
+
if (dialogMessageView.getVisibility() != newVisibility) {
dialogMessageView.setVisibility(newVisibility);
}
}
}
-
+
public void onClick(DialogInterface dialog, int which) {
mWhichButtonClicked = which;
}
-
+
+ @Override
public void onDismiss(DialogInterface dialog) {
-
+ removeDismissCallbacks();
getPreferenceManager().unregisterOnActivityDestroyListener(this);
-
+
mDialog = null;
onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
}
@@ -407,7 +435,7 @@
/**
* Called when the dialog is dismissed and should be used to save data to
* the {@link SharedPreferences}.
- *
+ *
* @param positiveResult Whether the positive button was clicked (true), or
* the negative button was clicked or the dialog was canceled (false).
*/
@@ -416,7 +444,7 @@
/**
* Gets the dialog that is shown by this preference.
- *
+ *
* @return The dialog, or null if a dialog is not being shown.
*/
public Dialog getDialog() {
@@ -427,11 +455,11 @@
* {@inheritDoc}
*/
public void onActivityDestroy() {
-
+
if (mDialog == null || !mDialog.isShowing()) {
return;
}
-
+
mDialog.dismiss();
}
@@ -466,7 +494,7 @@
private static class SavedState extends BaseSavedState {
boolean isDialogShowing;
Bundle dialogBundle;
-
+
public SavedState(Parcel source) {
super(source);
isDialogShowing = source.readInt() == 1;
@@ -495,5 +523,5 @@
}
};
}
-
+
}
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index e7dec0e..c0c71af 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -33,7 +33,7 @@
* <p>
* This preference will store a string into the SharedPreferences. This string will be the value
* from the {@link #setEntryValues(CharSequence[])} array.
- *
+ *
* @attr ref android.R.styleable#ListPreference_entries
* @attr ref android.R.styleable#ListPreference_entryValues
*/
@@ -193,7 +193,7 @@
/**
* Sets the value to the given index from the entry values.
- *
+ *
* @param index The index of the value to set.
*/
public void setValueIndex(int index) {
@@ -201,30 +201,30 @@
setValue(mEntryValues[index].toString());
}
}
-
+
/**
* Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
- *
+ *
* @return The value of the key.
*/
public String getValue() {
- return mValue;
+ return mValue;
}
-
+
/**
* Returns the entry corresponding to the current value.
- *
+ *
* @return The entry corresponding to the current value, or null.
*/
public CharSequence getEntry() {
int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null;
}
-
+
/**
* Returns the index of the given value (in the entry values array).
- *
+ *
* @param value The value whose index should be returned.
* @return The index of the value, or -1 if not found.
*/
@@ -238,22 +238,22 @@
}
return -1;
}
-
+
private int getValueIndex() {
return findIndexOfValue(mValue);
}
-
+
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
-
+
if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = getValueIndex();
- builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
+ builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
@@ -263,10 +263,10 @@
* click, and dismisses the dialog.
*/
ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
- dialog.dismiss();
+ postDismiss();
}
});
-
+
/*
* The typical interaction for list-based dialogs is to have
* click-on-an-item dismiss the dialog instead of the user having to
@@ -278,7 +278,7 @@
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
-
+
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) {
@@ -296,7 +296,7 @@
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
}
-
+
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
@@ -304,7 +304,7 @@
// No need to save instance state since it's persistent
return superState;
}
-
+
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
@@ -317,15 +317,15 @@
super.onRestoreInstanceState(state);
return;
}
-
+
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
-
+
private static class SavedState extends BaseSavedState {
String value;
-
+
public SavedState(Parcel source) {
super(source);
value = source.readString();
@@ -352,5 +352,5 @@
}
};
}
-
+
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 149f2b4..dd011a0 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1444,18 +1444,6 @@
}
public static final class Media implements AudioColumns {
-
- private static final String[] EXTERNAL_PATHS;
-
- static {
- String secondary_storage = System.getenv("SECONDARY_STORAGE");
- if (secondary_storage != null) {
- EXTERNAL_PATHS = secondary_storage.split(":");
- } else {
- EXTERNAL_PATHS = new String[0];
- }
- }
-
/**
* Get the content:// style URI for the audio media table on the
* given volume.
@@ -1469,14 +1457,9 @@
}
public static Uri getContentUriForPath(String path) {
- for (String ep : EXTERNAL_PATHS) {
- if (path.startsWith(ep)) {
- return EXTERNAL_CONTENT_URI;
- }
- }
-
- return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ?
- EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
+ return (path.startsWith(
+ Environment.getStorageDirectory().getAbsolutePath() + "/")
+ ? EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7a4ef5d..7370029 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7299,6 +7299,15 @@
public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application";
/**
+ * Specifies the package name currently configured to be the default application to perform
+ * the user-defined call redirection service with Telecom.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static final String CALL_REDIRECTION_DEFAULT_APPLICATION =
+ "call_redirection_default_application";
+
+ /**
* Specifies the package name currently configured to be the emergency assistance application
*
* @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
@@ -9131,6 +9140,19 @@
public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
/**
+ * Whether the wifi data connection should remain active even when higher
+ * priority networks like Ethernet are active, to keep both networks.
+ * In the case where higher priority networks are connected, wifi will be
+ * unused unless an application explicitly requests to use it.
+ *
+ * See ConnectivityService for more info.
+ *
+ * (0 = disabled, 1 = enabled)
+ * @hide
+ */
+ public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
+
+ /**
* Size of the event buffer for IP connectivity metrics.
* @hide
*/
@@ -9469,8 +9491,7 @@
* Use the old dnsmasq DHCP server for tethering instead of the framework implementation.
*
* Integer values are interpreted as boolean, and the absence of an explicit setting
- * is interpreted as |true|.
- * TODO: make the default |false|
+ * is interpreted as |false|.
* @hide
*/
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
@@ -11340,14 +11361,6 @@
public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
/**
- * Enable faster emergency phone call feature.
- * The value is a boolean (1 or 0).
- * @hide
- */
- public static final String FASTER_EMERGENCY_PHONE_CALL_ENABLED =
- "faster_emergency_phone_call_enabled";
-
- /**
* See RIL_PreferredNetworkType in ril.h
* @hide
*/
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index 119f5d0..4f4d62a 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -16,26 +16,23 @@
package android.security.net.config;
-import android.os.Environment;
-import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
+
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.InputStream;
import java.io.IOException;
-import java.security.cert.Certificate;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Set;
-import libcore.io.IoUtils;
-
-import com.android.org.conscrypt.Hex;
-import com.android.org.conscrypt.NativeCrypto;
import javax.security.auth.x500.X500Principal;
@@ -192,8 +189,36 @@
}
private String getHash(X500Principal name) {
- int hash = NativeCrypto.X509_NAME_hash_old(name);
- return Hex.intToHexString(hash, 8);
+ int hash = hashName(name);
+ return intToHexString(hash, 8);
+ }
+
+ private static final char[] DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ private static String intToHexString(int i, int minWidth) {
+ int bufLen = 8; // Max number of hex digits in an int
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[i & 0xf];
+ } while ((i >>>= 4) != 0 || (bufLen - cursor < minWidth));
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ // This code matches the code in X509_NAME_hash_old() in Conscrypt, which in turn matches
+ // the names of certificate files. It must be kept in sync.
+ private static int hashName(X500Principal principal) {
+ try {
+ byte[] digest = MessageDigest.getInstance("MD5").digest(principal.getEncoded());
+ int offset = 0;
+ return (((digest[offset++] & 0xff) << 0) | ((digest[offset++] & 0xff) << 8)
+ | ((digest[offset++] & 0xff) << 16) | ((digest[offset] & 0xff) << 24));
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
}
private X509Certificate readCertificate(String file) {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c861499..959534d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -33,6 +33,9 @@
public static final String FFLAG_PREFIX = "sys.fflag.";
public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
+ public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
+ public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
+ public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -44,6 +47,8 @@
DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+ DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "false");
+ DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b93afdf..bca2e11 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1421,6 +1421,10 @@
mServedView.getWindowToken() == appWindowToken) {
finishInputLocked();
}
+ if (mCurRootView != null &&
+ mCurRootView.getWindowToken() == appWindowToken) {
+ mCurRootView = null;
+ }
}
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index b591163..f90eab1 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -236,6 +236,7 @@
displayName = FileUtils.buildValidFatFilename(displayName);
final File before = getFileForDocId(docId);
+ final File beforeVisibleFile = getFileForDocId(docId, true);
final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
if (!before.renameTo(after)) {
throw new IllegalStateException("Failed to rename to " + after);
@@ -245,7 +246,6 @@
onDocIdChanged(docId);
onDocIdChanged(afterDocId);
- final File beforeVisibleFile = getFileForDocId(docId, true);
final File afterVisibleFile = getFileForDocId(afterDocId, true);
moveInMediaStore(beforeVisibleFile, afterVisibleFile);
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index c388148..fee8345 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -171,8 +171,7 @@
boolean debuggable);
private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
- String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge,
- boolean debuggable);
+ String abiToCopy, boolean extractNativeLibs, boolean debuggable);
private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
@@ -193,7 +192,7 @@
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
for (long apkHandle : handle.apkHandles) {
int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
- handle.extractNativeLibs, HAS_NATIVE_BRIDGE, handle.debuggable);
+ handle.extractNativeLibs, handle.debuggable);
if (res != INSTALL_SUCCEEDED) {
return res;
}
@@ -448,9 +447,6 @@
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
- private static final boolean HAS_NATIVE_BRIDGE =
- !"0".equals(SystemProperties.get("ro.dalvik.vm.native.bridge", "0"));
-
private static native int hasRenderscriptBitcode(long apkHandle);
public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 94c3933..486c836 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5369,6 +5369,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
@@ -5380,6 +5381,7 @@
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
@@ -5800,8 +5802,6 @@
for (int i = 0; i < N; i++) {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
- StatsLog.write_non_chained(StatsLog.BLE_SCAN_RESULT_RECEIVED, ws.get(i), ws.getName(i),
- numNewResults);
}
final List<WorkChain> workChains = ws.getWorkChains();
@@ -5810,8 +5810,6 @@
final WorkChain wc = workChains.get(i);
int uid = mapUid(wc.getAttributionUid());
getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
- StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED,
- wc.getUids(), wc.getTags(), numNewResults);
}
}
}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index bf31c7d..1ee4269 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -29,7 +29,6 @@
import com.android.internal.util.FastPrintWriter;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.File;
import java.io.FileInputStream;
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 7fd83bc..f6d80a5 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -34,9 +34,18 @@
/**
* Helper functions for dumping the state of system services.
* Test:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
*/
public final class DumpUtils {
+
+ /**
+ * List of component names that should be dumped in the bug report critical section.
+ *
+ * @hide
+ */
+ public static final ComponentName[] CRITICAL_SECTION_COMPONENTS = {
+ new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")
+ };
private static final String TAG = "DumpUtils";
private static final boolean DEBUG = false;
@@ -213,6 +222,45 @@
}
/**
+ * Return whether a package should be dumped in the critical section.
+ */
+ private static boolean isCriticalPackage(@Nullable ComponentName cname) {
+ if (cname == null) {
+ return false;
+ }
+
+ for (int i = 0; i < CRITICAL_SECTION_COMPONENTS.length; i++) {
+ if (cname.equals(CRITICAL_SECTION_COMPONENTS[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return whether a package name is considered to be part of the platform and in the critical
+ * section.
+ *
+ * @hide
+ */
+ public static boolean isPlatformCriticalPackage(@Nullable ComponentName.WithComponentName wcn) {
+ return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+ isCriticalPackage(wcn.getComponentName());
+ }
+
+ /**
+ * Return whether a package name is considered to be part of the platform but not in the the
+ * critical section.
+ *
+ * @hide
+ */
+ public static boolean isPlatformNonCriticalPackage(
+ @Nullable ComponentName.WithComponentName wcn) {
+ return (wcn != null) && isPlatformPackage(wcn.getComponentName()) &&
+ !isCriticalPackage(wcn.getComponentName());
+ }
+
+ /**
* Used for dumping providers and services. Return a predicate for a given filter string.
* @hide
*/
@@ -238,6 +286,16 @@
return DumpUtils::isNonPlatformPackage;
}
+ // Dump all platform-critical?
+ if ("all-platform-critical".equals(filterString)) {
+ return DumpUtils::isPlatformCriticalPackage;
+ }
+
+ // Dump all platform-non-critical?
+ if ("all-platform-non-critical".equals(filterString)) {
+ return DumpUtils::isPlatformNonCriticalPackage;
+ }
+
// Is the filter a component name? If so, do an exact match.
final ComponentName filterCname = ComponentName.unflattenFromString(filterString);
if (filterCname != null) {
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 9bf0948..7a01749 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -18,6 +18,7 @@
import android.annotation.AttrRes;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.StyleRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -50,6 +51,7 @@
super(context);
}
+ @UnsupportedAppUsage
public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index ab8be33..0ca6743 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -40,6 +41,7 @@
private int mMinimumHeight = 0;
+ @UnsupportedAppUsage
public ButtonBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 7ea3d6b..405436c 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
@@ -37,6 +38,7 @@
super(context, attrs, defStyleAttr);
}
+ @UnsupportedAppUsage
public DialogTitle(Context context, AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java
index c029bb2..3ea873b 100644
--- a/core/java/com/google/android/collect/Lists.java
+++ b/core/java/com/google/android/collect/Lists.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +34,7 @@
*
* @return a newly-created, initially-empty {@code ArrayList}
*/
+ @UnsupportedAppUsage
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index fc2c9fe..6ba3320 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import java.util.HashMap;
@@ -29,6 +30,7 @@
*
* @return a newly-created, initially-empty {@code HashMap}
*/
+ @UnsupportedAppUsage
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 494a957..d1a7d70 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -227,13 +227,13 @@
static_libs: [
"libgif",
"libseccomp_policy",
- "libselinux",
"libgrallocusage",
"libscrypt_static",
],
shared_libs: [
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"libmemtrack",
"libandroidfw",
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 6df23f7..a1f2377 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -58,6 +58,11 @@
int ret;
int fd;
+ if (name == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (env->ExceptionCheck()) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index c3ba9ba..9341d9a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -23,6 +23,7 @@
#include <atomic>
#include <fcntl.h>
#include <inttypes.h>
+#include <mutex>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -69,6 +70,7 @@
// Class state.
jclass mClass;
jmethodID mExecTransact;
+ jmethodID mGetInterfaceDescriptor;
// Object state.
jfieldID mObject;
@@ -328,8 +330,32 @@
env->DeleteGlobalRef(mObject);
}
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
+ const String16& getInterfaceDescriptor() const override
+ {
+ call_once(mPopulateDescriptor, [this] {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+
+ ALOGV("getInterfaceDescriptor() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
+
+ jstring descriptor = (jstring)env->CallObjectMethod(mObject, gBinderOffsets.mGetInterfaceDescriptor);
+
+ if (descriptor == nullptr) {
+ return;
+ }
+
+ static_assert(sizeof(jchar) == sizeof(char16_t), "");
+ const jchar* descriptorChars = env->GetStringChars(descriptor, nullptr);
+ const char16_t* rawDescriptor = reinterpret_cast<const char16_t*>(descriptorChars);
+ jsize rawDescriptorLen = env->GetStringLength(descriptor);
+ mDescriptor = String16(rawDescriptor, rawDescriptorLen);
+ env->ReleaseStringChars(descriptor, descriptorChars);
+ });
+
+ return mDescriptor;
+ }
+
+ status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
JNIEnv* env = javavm_to_jnienv(mVM);
@@ -378,7 +404,7 @@
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
- virtual status_t dump(int fd, const Vector<String16>& args)
+ status_t dump(int fd, const Vector<String16>& args) override
{
return 0;
}
@@ -386,6 +412,9 @@
private:
JavaVM* const mVM;
jobject const mObject; // GlobalRef to Java Binder
+
+ mutable std::once_flag mPopulateDescriptor;
+ mutable String16 mDescriptor;
};
// ----------------------------------------------------------------------------
@@ -939,6 +968,8 @@
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
+ gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
+ "()Ljava/lang/String;");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index dc04269..5eefc81 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -176,7 +176,6 @@
void** args = reinterpret_cast<void**>(arg);
jstring* javaNativeLibPath = (jstring*) args[0];
jboolean extractNativeLibs = *(jboolean*) args[1];
- jboolean hasNativeBridge = *(jboolean*) args[2];
ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
@@ -206,9 +205,7 @@
return INSTALL_FAILED_INVALID_APK;
}
- if (!hasNativeBridge) {
- return INSTALL_SUCCEEDED;
- }
+ return INSTALL_SUCCEEDED;
}
// Build local file path
@@ -489,9 +486,9 @@
static jint
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
- jboolean extractNativeLibs, jboolean hasNativeBridge, jboolean debuggable)
+ jboolean extractNativeLibs, jboolean debuggable)
{
- void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
+ void* args[] = { &javaNativeLibPath, &extractNativeLibs };
return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable,
copyFileIfChanged, reinterpret_cast<void*>(args));
}
@@ -597,7 +594,7 @@
"(J)V",
(void *)com_android_internal_content_NativeLibraryHelper_close},
{"nativeCopyNativeBinaries",
- "(JLjava/lang/String;Ljava/lang/String;ZZZ)I",
+ "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
(void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
{"nativeSumNativeBinaries",
"(JLjava/lang/String;Z)J",
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index c15b7ee..b3ff4db 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -32,8 +32,8 @@
#include <utils/misc.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::hasBpfSupport;
using android::bpf::parseBpfNetworkStatsDetail;
@@ -285,10 +285,6 @@
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
jboolean useBpfStats) {
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- return -1;
- }
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
@@ -308,6 +304,11 @@
if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
return -1;
} else {
+ ScopedUtfChars path8(env, path);
+ if (path8.c_str() == NULL) {
+ ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
+ return -1;
+ }
if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
limitUid, path8.c_str()) < 0)
return -1;
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index ed42e2e..30a9a01 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,6 +7,8 @@
joeo@google.com
kwekua@google.com
singhtejinder@google.com
+yanglu@google.com
+yaochen@google.com
# Frameworks
ogunwale@google.com
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 32975a5..fba2e51 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -61,3 +61,64 @@
SIGNAL_STRENGTH_GOOD = 3;
SIGNAL_STRENGTH_GREAT = 4;
}
+
+
+enum ServiceStateEnum {
+ /**
+ * Normal operation condition, the phone is registered
+ * with an operator either in home network or in roaming.
+ */
+ SERVICE_STATE_IN_SERVICE = 0;
+
+ /**
+ * Phone is not registered with any operator, the phone
+ * can be currently searching a new operator to register to, or not
+ * searching to registration at all, or registration is denied, or radio
+ * signal is not available.
+ */
+ SERVICE_STATE_OUT_OF_SERVICE = 1;
+
+ /**
+ * The phone is registered and locked. Only emergency numbers are allowed. {@more}
+ */
+ SERVICE_STATE_EMERGENCY_ONLY = 2;
+
+ /**
+ * Radio of telephony is explicitly powered off.
+ */
+ SERVICE_STATE_POWER_OFF = 3;
+}
+
+enum SimStateEnum {
+ SIM_STATE_UNKNOWN = 0;
+ /** SIM card state: no SIM card is available in the device */
+ SIM_STATE_ABSENT = 1;
+ /** SIM card state: Locked: requires the user's SIM PIN to unlock */
+ SIM_STATE_PIN_REQUIRED = 2;
+ /** SIM card state: Locked: requires the user's SIM PUK to unlock */
+ SIM_STATE_PUK_REQUIRED = 3;
+ /** SIM card state: Locked: requires a network PIN to unlock */
+ SIM_STATE_NETWORK_LOCKED = 4;
+ /** SIM card state: Ready */
+ SIM_STATE_READY = 5;
+ /** SIM card state: SIM Card is NOT READY */
+ SIM_STATE_NOT_READY = 6;
+ /** SIM card state: SIM Card Error, permanently disabled */
+ SIM_STATE_PERM_DISABLED = 7;
+ /** SIM card state: SIM Card Error, present but faulty */
+ SIM_STATE_CARD_IO_ERROR = 8;
+ /** SIM card state: SIM Card restricted, present but not usable due to
+ * carrier restrictions.
+ */
+ SIM_STATE_CARD_RESTRICTED = 9;
+ /**
+ * SIM card state: Loaded: SIM card applications have been loaded
+ * @hide
+ */
+ SIM_STATE_LOADED = 10;
+ /**
+ * SIM card state: SIM Card is present
+ * @hide
+ */
+ SIM_STATE_PRESENT = 11;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ac9617c..0dabcd7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -138,7 +138,6 @@
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
<protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
- <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
@@ -1441,6 +1440,7 @@
<!-- Allows SetupWizard to call methods in Networking services
<p>Not for use by any other third-party or privileged applications.
+ @SystemApi
@hide This should only be used by SetupWizard.
-->
<permission android:name="android.permission.NETWORK_SETUP_WIZARD"
@@ -1827,6 +1827,13 @@
<permission android:name="android.permission.BIND_SCREENING_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by a {@link android.telecom.CallRedirectionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
@deprecated {@link android.telecom.ConnectionService}s should require
diff --git a/core/res/res/values-mcc262-mnc02/strings.xml b/core/res/res/values-mcc262-mnc02/strings.xml
deleted file mode 100644
index 2b89401..0000000
--- a/core/res/res/values-mcc262-mnc02/strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2017, Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Do not translate. Template for showing mobile network operator name while WFC is active -->
- <string-array name="wfcSpnFormats">
- <item>%s</item>
- <item>%s Wi-Fi Calling</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc370/strings.xml b/core/res/res/values-mcc302-mnc370/strings.xml
deleted file mode 100644
index f5b8496..0000000
--- a/core/res/res/values-mcc302-mnc370/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Template for showing mobile network operator name while WFC is active -->
- <string-array name="wfcSpnFormats">
- <item>%s</item>
- <item>%s Wi-Fi</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc720/strings.xml b/core/res/res/values-mcc302-mnc720/strings.xml
deleted file mode 100644
index f5b8496..0000000
--- a/core/res/res/values-mcc302-mnc720/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Template for showing mobile network operator name while WFC is active -->
- <string-array name="wfcSpnFormats">
- <item>%s</item>
- <item>%s Wi-Fi</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 632e439..477b17e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3463,4 +3463,12 @@
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
<bool name="config_swipe_up_gesture_setting_available">false</bool>
+ <!-- Pre-scale volume at volume step 1 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index1">50%</fraction>
+
+ <!-- Pre-scale volume at volume step 2 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index2">70%</fraction>
+
+ <!-- Pre-scale volume at volume step 3 for Absolute Volume -->
+ <fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3c5159c..2549dd0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -240,10 +240,31 @@
<item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item>
</string-array>
<!-- Template for showing mobile network operator name while WFC is active -->
- <string-array name="wfcSpnFormats">
- <item>%s</item>
- <item>%s Wi-Fi Calling</item>
+ <string-array name="wfcSpnFormats" translatable="false">
+ <item>@string/wfcSpnFormat_spn</item>
+ <item>@string/wfcSpnFormat_spn_wifi_calling</item>
+ <item>@string/wfcSpnFormat_wlan_call</item>
+ <item>@string/wfcSpnFormat_spn_wlan_call</item>
+ <item>@string/wfcSpnFormat_spn_wifi</item>
+ <item>@string/wfcSpnFormat_wifi_calling_bar_spn</item>
+ <item>@string/wfcSpnFormat_spn_vowifi</item>
</string-array>
+
+ <!-- Spn during Wi-Fi Calling: "<operator>" -->
+ <string name="wfcSpnFormat_spn"><xliff:g id="spn" example="Operator">%s</xliff:g></string>
+ <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi Calling" -->
+ <string name="wfcSpnFormat_spn_wifi_calling"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi Calling</string>
+ <!-- Spn during Wi-Fi Calling: "WLAN Call" -->
+ <string name="wfcSpnFormat_wlan_call">WLAN Call</string>
+ <!-- Spn during Wi-Fi Calling: "<operator> WLAN Call" -->
+ <string name="wfcSpnFormat_spn_wlan_call"><xliff:g id="spn" example="Operator">%s</xliff:g> WLAN Call</string>
+ <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi" -->
+ <string name="wfcSpnFormat_spn_wifi"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi</string>
+ <!-- Spn during Wi-Fi Calling: "WiFi Calling | <operator>" -->
+ <string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string>
+ <!-- Spn during Wi-Fi Calling: "<operator> VoWifi" -->
+ <string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string>
+
<!-- WFC, summary for Disabled -->
<string name="wifi_calling_off_summary">Off</string>
<!-- WFC, summary for Wi-Fi Preferred -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index de5dc43..e9a54f1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3393,4 +3393,9 @@
<java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
<java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+
+ <!-- For Bluetooth AbsoluteVolume -->
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" />
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" />
+ <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />
</resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index fb78b3b..7b3d940 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -109,12 +109,12 @@
<!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
visual voicemail code for Orange: 21101 -->
- <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366" />
+ <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051" />
<!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
visual voicemail code for EE: 887 -->
- <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726" />
+ <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
<!-- Georgia: 4 digits, known premium codes listed -->
<shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -189,11 +189,14 @@
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
+ <!-- Nigeria -->
+ <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
+
<!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
<!-- New Zealand: 3-4 digits, known premium codes listed -->
- <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
+ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
<!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="pe" pattern="\\d{4,5}" free="9963" />
@@ -209,7 +212,7 @@
<!-- Portugal: 5 digits, plus EU:
http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
- <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262" />
+ <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262|12666" />
<!-- Qatar: 1-5 digits (standard system default, not country specific) -->
<shortcode country="qa" pattern="\\d{1,5}" free="92451" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index e0d5393..041fb7e 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -47,7 +47,6 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- conscrypt \
telephony-common \
org.apache.http.legacy \
android.test.base \
@@ -67,10 +66,6 @@
# Disable AAPT2 because the hacks below depend on the AAPT rules implementation
LOCAL_USE_AAPT2 := false
-# When AAPT2 is enabled it will need --warn-manifest-validation to fix:
-# frameworks/base/core/tests/coretests/AndroidManifest.xml:26: error: unknown element <meta-data> found.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-# LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
# Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
index 9727593..3f163de 100644
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ b/core/tests/coretests/apks/install_multi_package/Android.mk
@@ -8,10 +8,6 @@
LOCAL_PACKAGE_NAME := install_multi_package
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml:46: error: unexpected element <package> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
#include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
index 679327c..745b4d3 100644
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.mk
@@ -6,9 +6,5 @@
LOCAL_PACKAGE_NAME := install_verifier_bad
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_bad/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
index 7d621b3..150fd8d 100644
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_good/Android.mk
@@ -6,9 +6,5 @@
LOCAL_PACKAGE_NAME := install_verifier_good
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_good/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
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 0000000..7218b3a2
--- /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/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 584257b..e248a77 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -45,7 +45,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
import org.junit.After;
import org.junit.Assert;
@@ -63,7 +63,7 @@
@Before
public void setUp() {
- mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest");
+ mTmpDir = TestIoUtils.createTemporaryDirectory("DexMetadataHelperTest");
}
@After
diff --git a/core/tests/coretests/src/android/net/LocalSocketTest.java b/core/tests/coretests/src/android/net/LocalSocketTest.java
index 1349844..1286b13 100644
--- a/core/tests/coretests/src/android/net/LocalSocketTest.java
+++ b/core/tests/coretests/src/android/net/LocalSocketTest.java
@@ -22,6 +22,7 @@
import android.net.LocalSocketAddress;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
import java.io.FileDescriptor;
@@ -39,6 +40,20 @@
ls = new LocalSocket();
+ try {
+ ls.connect(new LocalSocketAddress(null));
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // pass
+ }
+
+ try {
+ ls.bind(new LocalSocketAddress(null));
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // pass
+ }
+
ls.connect(new LocalSocketAddress("android.net.LocalSocketTest"));
ls1 = ss.accept();
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 0bc3a2d..17e34be 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -32,7 +32,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
import libcore.io.Streams;
import com.google.android.collect.Sets;
@@ -79,7 +78,7 @@
@After
public void tearDown() throws Exception {
- IoUtils.deleteContents(mDir);
+ FileUtils.deleteContents(mDir);
FileUtils.deleteContents(mTarget);
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 02e0d02..32790e5 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -238,7 +238,6 @@
Settings.Global.EUICC_SUPPORTED_COUNTRIES,
Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
Settings.Global.FANCY_IME_ANIMATIONS,
- Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FORCED_APP_STANDBY_ENABLED,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
@@ -457,6 +456,7 @@
Settings.Global.WFC_IMS_MODE,
Settings.Global.WFC_IMS_ROAMING_ENABLED,
Settings.Global.WFC_IMS_ROAMING_MODE,
+ Settings.Global.WIFI_ALWAYS_REQUESTED,
Settings.Global.WIFI_BADGING_THRESHOLDS,
Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
@@ -527,6 +527,7 @@
Settings.Secure.BACKUP_ENABLED,
Settings.Secure.BACKUP_PROVISIONED,
Settings.Secure.BACKUP_TRANSPORT,
+ Settings.Secure.CALL_REDIRECTION_DEFAULT_APPLICATION,
Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
Settings.Secure.CARRIER_APPS_HANDLED,
Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index f8e3b4d..872b71a 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -117,7 +117,7 @@
@Test
public void testFormatSameDayTime() {
// This test assumes a default DateFormat.is24Hour setting.
- DateFormat.is24Hour = null;
+ DateFormat.set24HourTimePref(null);
Date date = new Date(109, 0, 19, 3, 30, 15);
long fixedTime = date.getTime();
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index 45b19bc..a44b860 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -15,8 +15,11 @@
*/
package com.android.internal.util;
+import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
import static com.android.internal.util.DumpUtils.filterRecord;
import static com.android.internal.util.DumpUtils.isNonPlatformPackage;
+import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage;
+import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage;
import static com.android.internal.util.DumpUtils.isPlatformPackage;
import android.content.ComponentName;
@@ -25,7 +28,7 @@
/**
* Run with:
- atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java
+ atest FrameworksCoreTests:DumpUtilsTest
*/
public class DumpUtilsTest extends TestCase {
@@ -89,6 +92,32 @@
assertTrue(isNonPlatformPackage(wcn("com.google.def/abc")));
}
+ public void testIsPlatformCriticalPackage() {
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertTrue(isPlatformCriticalPackage(() -> componentName));
+ assertTrue(isPlatformPackage(componentName));
+ }
+ assertFalse(isPlatformCriticalPackage(wcn("com.google.p/abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android.def/abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android.abc")));
+ assertFalse(isPlatformCriticalPackage(wcn("com.android")));
+ assertFalse(isPlatformCriticalPackage(wcn(null)));
+ assertFalse(isPlatformCriticalPackage(null));
+ }
+
+ public void testIsPlatformNonCriticalPackage() {
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertFalse(isPlatformNonCriticalPackage(() -> componentName));
+ }
+ assertTrue(isPlatformNonCriticalPackage(wcn("android/abc")));
+ assertTrue(isPlatformNonCriticalPackage(wcn("android.abc/abc")));
+ assertTrue(isPlatformNonCriticalPackage(wcn("com.android.def/abc")));
+
+ assertFalse(isPlatformNonCriticalPackage(wcn("com.google.def/abc")));
+ assertFalse(isPlatformNonCriticalPackage(wcn(null)));
+ assertFalse(isPlatformNonCriticalPackage(null));
+ }
+
public void testFilterRecord() {
assertFalse(filterRecord(null).test(wcn("com.google.p/abc")));
assertFalse(filterRecord(null).test(wcn("com.android.p/abc")));
@@ -105,6 +134,19 @@
assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc")));
assertFalse(filterRecord("all-non-platform").test(wcn(null)));
+ for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
+ assertTrue(filterRecord("all-platform-critical").test((() -> componentName)));
+ assertFalse(filterRecord("all-platform-non-critical").test((() -> componentName)));
+ assertTrue(filterRecord("all-platform").test((() -> componentName)));
+ }
+ assertFalse(filterRecord("all-platform-critical").test(wcn("com.google.p/abc")));
+ assertFalse(filterRecord("all-platform-critical").test(wcn("com.android.p/abc")));
+ assertFalse(filterRecord("all-platform-critical").test(wcn(null)));
+
+ assertTrue(filterRecord("all-platform-non-critical").test(wcn("com.android.p/abc")));
+ assertFalse(filterRecord("all-platform-non-critical").test(wcn("com.google.p/abc")));
+ assertFalse(filterRecord("all-platform-non-critical").test(wcn(null)));
+
// Partial string match.
assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc")));
assertFalse(filterRecord("abc").test(wcn("com.google.p/.def")));
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
index edad4b2..97a3d00 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -20,4 +20,6 @@
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
index 3fae8e1..a347025 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -20,4 +20,6 @@
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
index c352c05..e4819e1 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -20,4 +20,6 @@
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index ab3faf0..8656781 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -21,6 +21,8 @@
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
my_package_prefix := com.android.server.om.hosttest.framework_overlay
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6f52fbd..73c10d2 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" />
@@ -204,6 +210,11 @@
<allow-in-power-save-except-idle package="com.android.providers.calendar" />
<allow-in-power-save-except-idle package="com.android.providers.contacts" />
+ <!-- The PAC proxy process must have network access, otherwise no app will
+ be able to connect to the internet when such a proxy is in use, since
+ all outgoing connections originate from this app. -->
+ <allow-in-power-save-except-idle package="com.android.proxyhandler" />
+
<!-- These are the packages that are white-listed to be able to run as system user -->
<system-user-whitelisted-app package="com.android.settings" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 82b6a22..0082f4b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -316,6 +316,7 @@
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
<permission name="android.permission.REAL_GET_TASKS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index 522db3c..b463dd8 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -21,8 +21,6 @@
key 0x126 DPAD_DOWN
key 0x127 DPAD_LEFT
-key 0x120 BUTTON_SELECT
-key 0x123 BUTTON_START
key 0x12e BUTTON_A
key 0x12d BUTTON_B
key 0x12f BUTTON_X
@@ -34,9 +32,6 @@
key 0x121 BUTTON_THUMBL
key 0x122 BUTTON_THUMBR
-# PS key
-key 0x2d0 BUTTON_MODE
-
# Left Analog Stick
axis 0x00 X
axis 0x01 Y
@@ -74,3 +69,11 @@
# Square
# axis 0x37
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x120 BUTTON_SELECT
+# Start
+key 0x123 BUTTON_START
+# PS key
+key 0x2d0 BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
new file mode 100644
index 0000000..3d93f0f
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
@@ -0,0 +1,57 @@
+# 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.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.12
+# and when connected over Bluetooth
+#
+
+key 0x220 DPAD_UP
+key 0x223 DPAD_RIGHT
+key 0x221 DPAD_DOWN
+key 0x222 DPAD_LEFT
+
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x134 BUTTON_X
+key 0x133 BUTTON_Y
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+key 0x13d BUTTON_THUMBL
+key 0x13e BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# L2 trigger
+axis 0x02 LTRIGGER
+
+# R2 trigger
+axis 0x05 RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a BUTTON_SELECT
+# Start
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
new file mode 100644
index 0000000..3d93f0f
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
@@ -0,0 +1,57 @@
+# 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.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.12
+# and when connected over Bluetooth
+#
+
+key 0x220 DPAD_UP
+key 0x223 DPAD_RIGHT
+key 0x221 DPAD_DOWN
+key 0x222 DPAD_LEFT
+
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x134 BUTTON_X
+key 0x133 BUTTON_Y
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+key 0x13d BUTTON_THUMBL
+key 0x13e BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# L2 trigger
+axis 0x02 LTRIGGER
+
+# R2 trigger
+axis 0x05 RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a BUTTON_SELECT
+# Start
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
new file mode 100644
index 0000000..5fe35f7
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
@@ -0,0 +1,57 @@
+# 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.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.12 and when
+# connected over USB
+#
+
+key 0x220 DPAD_UP
+key 0x223 DPAD_RIGHT
+key 0x221 DPAD_DOWN
+key 0x222 DPAD_LEFT
+
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x134 BUTTON_X
+key 0x133 BUTTON_Y
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+key 0x13d BUTTON_THUMBL
+key 0x13e BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# L2 trigger
+axis 0x02 LTRIGGER
+
+# R2 trigger
+axis 0x05 RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a BUTTON_SELECT
+# Start
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_05c4.kl b/data/keyboards/Vendor_054c_Product_05c4.kl
index a1284a4..cd7ab1f 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4.kl
@@ -60,7 +60,6 @@
key 0x138 BUTTON_SELECT
# Options
key 0x139 BUTTON_START
-
# PS key
key 0x13c BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+# and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+# and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
new file mode 100644
index 0000000..d38bdec
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.10 and when
+# connected over USB
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc.kl b/data/keyboards/Vendor_054c_Product_09cc.kl
index a1284a4..cd7ab1f 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc.kl
@@ -60,7 +60,6 @@
key 0x138 BUTTON_SELECT
# Options
key 0x139 BUTTON_START
-
# PS key
key 0x13c BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+# and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+# and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
new file mode 100644
index 0000000..d38bdec
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.10 and when
+# connected over USB
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_0ba0.kl b/data/keyboards/Vendor_054c_Product_0ba0.kl
new file mode 100644
index 0000000..bc6fc3b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0ba0.kl
@@ -0,0 +1,70 @@
+# 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.
+
+#
+# Sony Playstation(R) DualShock 4 USB Dongle
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x130 BUTTON_X
+# Cross
+key 0x131 BUTTON_A
+# Circle
+key 0x132 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+key 0x136 BUTTON_L2
+key 0x137 BUTTON_R2
+
+# L2 axis
+axis 0x03 LTRIGGER
+# R2 axis
+axis 0x04 RTRIGGER
+
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# Left stick click
+key 0x13a BUTTON_THUMBL
+# Right stick click
+key 0x13b BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x138 BUTTON_SELECT
+# Options
+key 0x139 BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# Touchpad press
+# The touchpad for this joystick will become a separate input device in future releases
+# and this button will be equivalent to left mouse button
+# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
+key 0x13d BUTTON_1
diff --git a/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl
new file mode 100644
index 0000000..8b85a38
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl
@@ -0,0 +1,67 @@
+# 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.
+
+#
+# Sony Playstation(R) DualShock 4 USB Dongle
+# - Version 0x8111 is for Linux hid-sony driver >=4.10
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134 BUTTON_X
+# Cross
+key 0x130 BUTTON_A
+# Circle
+key 0x131 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# L2 axis
+axis 0x02 LTRIGGER
+# R2 axis
+axis 0x05 RTRIGGER
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a BUTTON_SELECT
+# Options
+key 0x13b BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 5814df5..8fd02c0 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -472,8 +472,8 @@
* <tr>
* <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.039 \\
- * \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.039 \end{cases}
+ * C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.04045 \\
+ * \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases}
* \end{equation}\)
* </td>
* </tr>
@@ -1484,7 +1484,7 @@
"Display P3",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
ILLUMINANT_D65,
- new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.039, 2.4),
+ new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
Named.DISPLAY_P3.ordinal()
);
sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 3821bc7..21ce1b8 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -27,7 +27,6 @@
import android.system.OsConstants;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.IOException;
diff --git a/keystore/OWNERS b/keystore/OWNERS
new file mode 100644
index 0000000..a63ca46
--- /dev/null
+++ b/keystore/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+robbarnes@google.com
+swillden@google.com
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index e39926b..140001d 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -43,11 +43,14 @@
"AssetManager2.cpp",
"AttributeResolution.cpp",
"ChunkIterator.cpp",
+ "ConfigDescription.cpp",
"Idmap.cpp",
"LoadedArsc.cpp",
+ "Locale.cpp",
"LocaleData.cpp",
"misc.cpp",
"ObbFile.cpp",
+ "PosixUtils.cpp",
"ResourceTypes.cpp",
"ResourceUtils.cpp",
"StreamingZipInflater.cpp",
@@ -135,9 +138,11 @@
"tests/AttributeResolution_test.cpp",
"tests/ByteBucketArray_test.cpp",
"tests/Config_test.cpp",
+ "tests/ConfigDescription_test.cpp",
"tests/ConfigLocale_test.cpp",
"tests/Idmap_test.cpp",
"tests/LoadedArsc_test.cpp",
+ "tests/Locale_test.cpp",
"tests/ResourceUtils_test.cpp",
"tests/ResTable_test.cpp",
"tests/Split_test.cpp",
@@ -152,6 +157,7 @@
srcs: [
"tests/BackupData_test.cpp",
"tests/ObbFile_test.cpp",
+ "tests/PosixUtils_test.cpp",
],
shared_libs: common_test_libs + ["libui"],
},
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 8f58f74..66a5477 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -39,7 +39,7 @@
static const std::string kResourcesArsc("resources.arsc");
-ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path)
+ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path)
: zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9c1629b..04cc5bb 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -67,10 +67,10 @@
}
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
- bool invalidate_caches) {
+ bool invalidate_caches, bool filter_incompatible_configs) {
apk_assets_ = apk_assets;
BuildDynamicRefTable();
- RebuildFilterList();
+ RebuildFilterList(filter_incompatible_configs);
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
@@ -825,7 +825,7 @@
return 0u;
}
-void AssetManager2::RebuildFilterList() {
+void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
for (PackageGroup& group : package_groups_) {
for (ConfiguredPackage& impl : group.packages_) {
// Destroy it.
@@ -841,7 +841,7 @@
for (auto iter = spec->types; iter != iter_end; ++iter) {
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
- if (this_config.match(configuration_)) {
+ if (!filter_incompatible_configs || this_config.match(configuration_)) {
group.configurations.push_back(this_config);
group.types.push_back(*iter);
}
diff --git a/tools/aapt2/ConfigDescription.cpp b/libs/androidfw/ConfigDescription.cpp
similarity index 98%
rename from tools/aapt2/ConfigDescription.cpp
rename to libs/androidfw/ConfigDescription.cpp
index f621660..1f3a89e 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/libs/androidfw/ConfigDescription.cpp
@@ -14,22 +14,16 @@
* limitations under the License.
*/
-#include "ConfigDescription.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/Locale.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+#include "androidfw/Util.h"
#include <string>
#include <vector>
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
-#include "Locale.h"
-#include "SdkConstants.h"
-#include "util/Util.h"
-
-using android::ResTable_config;
-using android::StringPiece;
-
-namespace aapt {
+namespace android {
static const char* kWildcardName = "any";
@@ -883,7 +877,7 @@
}
std::string ConfigDescription::to_string() const {
- const android::String8 str = toString();
+ const String8 str = toString();
return std::string(str.string(), str.size());
}
@@ -996,4 +990,4 @@
return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 04d506a..21f023d 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -203,6 +203,39 @@
return true;
}
+LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
+ : loadedPackage_(lp),
+ typeIndex_(ti),
+ entryIndex_(ei),
+ typeIndexEnd_(lp->resource_ids_.size() + 1) {
+ while (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] == 0) {
+ typeIndex_++;
+ }
+}
+
+LoadedPackage::iterator& LoadedPackage::iterator::operator++() {
+ while (typeIndex_ < typeIndexEnd_) {
+ if (entryIndex_ + 1 < loadedPackage_->resource_ids_[typeIndex_]) {
+ entryIndex_++;
+ break;
+ }
+ entryIndex_ = 0;
+ typeIndex_++;
+ if (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] != 0) {
+ break;
+ }
+ }
+ return *this;
+}
+
+uint32_t LoadedPackage::iterator::operator*() const {
+ if (typeIndex_ >= typeIndexEnd_) {
+ return 0;
+ }
+ return make_resid(loadedPackage_->package_id_, typeIndex_ + loadedPackage_->type_id_offset_,
+ entryIndex_);
+}
+
const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
uint16_t entry_index) {
uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
@@ -488,6 +521,7 @@
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
if (builder_ptr == nullptr) {
builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+ loaded_package->resource_ids_.set(type_spec->id, entry_count);
} else {
LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
type_spec->id);
diff --git a/tools/aapt2/Locale.cpp b/libs/androidfw/Locale.cpp
similarity index 98%
rename from tools/aapt2/Locale.cpp
rename to libs/androidfw/Locale.cpp
index d81921f..2870066 100644
--- a/tools/aapt2/Locale.cpp
+++ b/libs/androidfw/Locale.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include "Locale.h"
+#include "androidfw/Locale.h"
+#include "androidfw/Util.h"
#include <ctype.h>
@@ -22,12 +23,10 @@
#include <string>
#include <vector>
-#include "util/Util.h"
-
using ::android::ResTable_config;
using ::android::StringPiece;
-namespace aapt {
+namespace android {
void LocaleValue::set_language(const char* language_chars) {
size_t i = 0;
@@ -258,4 +257,4 @@
}
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
new file mode 100644
index 0000000..df0dd7c
--- /dev/null
+++ b/libs/androidfw/PosixUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+// nothing to see here
+#else
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "android-base/logging.h"
+
+#include "androidfw/PosixUtils.h"
+
+namespace {
+
+std::unique_ptr<std::string> ReadFile(int fd) {
+ std::unique_ptr<std::string> str(new std::string());
+ char buf[1024];
+ ssize_t r;
+ while ((r = read(fd, buf, sizeof(buf))) > 0) {
+ str->append(buf, r);
+ }
+ if (r != 0) {
+ return nullptr;
+ }
+ return str;
+}
+
+}
+
+namespace android {
+namespace util {
+
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) {
+ int stdout[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stdout) != 0) {
+ PLOG(ERROR) << "pipe";
+ return nullptr;
+ }
+
+ int stderr[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stderr) != 0) {
+ PLOG(ERROR) << "pipe";
+ close(stdout[0]);
+ close(stdout[1]);
+ return nullptr;
+ }
+
+ char const** argv0 = (char const**)malloc(sizeof(char*) * (argv.size() + 1));
+ for (size_t i = 0; i < argv.size(); i++) {
+ argv0[i] = argv[i].c_str();
+ }
+ argv0[argv.size()] = nullptr;
+ switch (fork()) {
+ case -1: // error
+ free(argv0);
+ PLOG(ERROR) << "fork";
+ return nullptr;
+ case 0: // child
+ close(stdout[0]);
+ if (dup2(stdout[1], STDOUT_FILENO) == -1) {
+ abort();
+ }
+ close(stderr[0]);
+ if (dup2(stderr[1], STDERR_FILENO) == -1) {
+ abort();
+ }
+ execvp(argv0[0], const_cast<char* const*>(argv0));
+ PLOG(ERROR) << "execv";
+ abort();
+ default: // parent
+ free(argv0);
+ close(stdout[1]);
+ close(stderr[1]);
+ int status;
+ wait(&status);
+ if (!WIFEXITED(status)) {
+ return nullptr;
+ }
+ std::unique_ptr<ProcResult> result(new ProcResult());
+ result->status = status;
+ const auto out = ReadFile(stdout[0]);
+ result->stdout = out ? *out : "";
+ close(stdout[0]);
+ const auto err = ReadFile(stderr[0]);
+ result->stderr = err ? *err : "";
+ close(stderr[0]);
+ return result;
+ }
+}
+
+} // namespace util
+} // namespace android
+#endif
diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp
index 575cd18..59c9d64 100644
--- a/libs/androidfw/Util.cpp
+++ b/libs/androidfw/Util.cpp
@@ -16,6 +16,7 @@
#include "androidfw/Util.h"
+#include <algorithm>
#include <string>
#include "utils/ByteOrder.h"
@@ -67,5 +68,28 @@
return utf8;
}
+static std::vector<std::string> SplitAndTransform(
+ const StringPiece& str, char sep, const std::function<char(char)>& f) {
+ std::vector<std::string> parts;
+ const StringPiece::const_iterator end = std::end(str);
+ StringPiece::const_iterator start = std::begin(str);
+ StringPiece::const_iterator current;
+ do {
+ current = std::find(start, end, sep);
+ parts.emplace_back(str.substr(start, current).to_string());
+ if (f) {
+ std::string& part = parts.back();
+ std::transform(part.begin(), part.end(), part.begin(), f);
+ }
+ start = current + 1;
+ } while (current != end);
+ return parts;
+}
+
+std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep) {
+ return SplitAndTransform(str, sep, ::tolower);
+}
+
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 69702e3..db2d038 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -27,6 +27,9 @@
#include "androidfw/LoadedArsc.h"
#include "androidfw/misc.h"
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
+
namespace android {
class LoadedIdmap;
@@ -88,9 +91,9 @@
// Creates an Asset from any file on the file system.
static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
- ApkAssets(void* unmanaged_handle, const std::string& path);
+ ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path);
- using ZipArchivePtr = std::unique_ptr<void, void(*)(void*)>;
+ using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>;
ZipArchivePtr zip_handle_;
const std::string path_;
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ad31f69..2f0ee01 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -96,7 +96,12 @@
// Only pass invalidate_caches=false when it is known that the structure
// change in ApkAssets is due to a safe addition of resources with completely
// new resource IDs.
- bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+ //
+ // Only pass in filter_incompatible_configs=false when you want to load all
+ // configurations (including incompatible ones) such as when constructing an
+ // idmap.
+ bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true,
+ bool filter_incompatible_configs = true);
inline const std::vector<const ApkAssets*> GetApkAssets() const {
return apk_assets_;
@@ -274,7 +279,7 @@
// Triggers the re-construction of lists of types that match the set configuration.
// This should always be called when mutating the AssetManager's configuration or ApkAssets set.
- void RebuildFilterList();
+ void RebuildFilterList(bool filter_incompatible_configs = true);
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
diff --git a/tools/aapt2/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
similarity index 84%
rename from tools/aapt2/ConfigDescription.h
rename to libs/androidfw/include/androidfw/ConfigDescription.h
index f719552..29424c4 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -14,21 +14,52 @@
* limitations under the License.
*/
-#ifndef AAPT_CONFIG_DESCRIPTION_H
-#define AAPT_CONFIG_DESCRIPTION_H
+#ifndef ANDROIDFW_CONFIG_DESCRIPTION_H
+#define ANDROIDFW_CONFIG_DESCRIPTION_H
#include <ostream>
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
-namespace aapt {
+namespace android {
+
+using ApiVersion = int;
+
+enum : ApiVersion {
+ SDK_CUPCAKE = 3,
+ SDK_DONUT = 4,
+ SDK_ECLAIR = 5,
+ SDK_ECLAIR_0_1 = 6,
+ SDK_ECLAIR_MR1 = 7,
+ SDK_FROYO = 8,
+ SDK_GINGERBREAD = 9,
+ SDK_GINGERBREAD_MR1 = 10,
+ SDK_HONEYCOMB = 11,
+ SDK_HONEYCOMB_MR1 = 12,
+ SDK_HONEYCOMB_MR2 = 13,
+ SDK_ICE_CREAM_SANDWICH = 14,
+ SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+ SDK_JELLY_BEAN = 16,
+ SDK_JELLY_BEAN_MR1 = 17,
+ SDK_JELLY_BEAN_MR2 = 18,
+ SDK_KITKAT = 19,
+ SDK_KITKAT_WATCH = 20,
+ SDK_LOLLIPOP = 21,
+ SDK_LOLLIPOP_MR1 = 22,
+ SDK_MARSHMALLOW = 23,
+ SDK_NOUGAT = 24,
+ SDK_NOUGAT_MR1 = 25,
+ SDK_O = 26,
+ SDK_O_MR1 = 27,
+ SDK_P = 28,
+};
/*
* Subclass of ResTable_config that adds convenient
* initialization and comparison methods.
*/
-struct ConfigDescription : public android::ResTable_config {
+struct ConfigDescription : public ResTable_config {
/**
* Returns an immutable default config.
*/
@@ -53,11 +84,11 @@
ConfigDescription();
ConfigDescription(const android::ResTable_config& o); // NOLINT(implicit)
ConfigDescription(const ConfigDescription& o);
- ConfigDescription(ConfigDescription&& o);
+ ConfigDescription(ConfigDescription&& o) noexcept;
ConfigDescription& operator=(const android::ResTable_config& o);
ConfigDescription& operator=(const ConfigDescription& o);
- ConfigDescription& operator=(ConfigDescription&& o);
+ ConfigDescription& operator=(ConfigDescription&& o) noexcept;
ConfigDescription CopyWithoutSdkVersion() const;
@@ -124,7 +155,7 @@
*static_cast<android::ResTable_config*>(this) = o;
}
-inline ConfigDescription::ConfigDescription(ConfigDescription&& o) {
+inline ConfigDescription::ConfigDescription(ConfigDescription&& o) noexcept {
*this = o;
}
@@ -141,7 +172,7 @@
return *this;
}
-inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) {
+inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) noexcept {
*this = o;
return *this;
}
@@ -180,6 +211,6 @@
return out << o.toString().string();
}
-} // namespace aapt
+} // namespace android
-#endif // AAPT_CONFIG_DESCRIPTION_H
+#endif // ANDROIDFW_CONFIG_DESCRIPTION_H
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fc..349b379 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,55 @@
class LoadedPackage {
public:
+ class iterator {
+ public:
+ iterator& operator=(const iterator& rhs) {
+ loadedPackage_ = rhs.loadedPackage_;
+ typeIndex_ = rhs.typeIndex_;
+ entryIndex_ = rhs.entryIndex_;
+ return *this;
+ }
+
+ bool operator==(const iterator& rhs) const {
+ return loadedPackage_ == rhs.loadedPackage_ &&
+ typeIndex_ == rhs.typeIndex_ &&
+ entryIndex_ == rhs.entryIndex_;
+ }
+
+ bool operator!=(const iterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ iterator operator++(int) {
+ size_t prevTypeIndex_ = typeIndex_;
+ size_t prevEntryIndex_ = entryIndex_;
+ operator++();
+ return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
+ }
+
+ iterator& operator++();
+
+ uint32_t operator*() const;
+
+ private:
+ friend class LoadedPackage;
+
+ iterator(const LoadedPackage* lp, size_t ti, size_t ei);
+
+ const LoadedPackage* loadedPackage_;
+ size_t typeIndex_;
+ size_t entryIndex_;
+ const size_t typeIndexEnd_; // STL style end, so one past the last element
+ };
+
+ iterator begin() const {
+ return iterator(this, 0, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, resource_ids_.size() + 1, 0);
+ }
+
static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
const LoadedIdmap* loaded_idmap, bool system,
bool load_as_shared_library);
@@ -182,6 +231,7 @@
bool overlay_ = false;
ByteBucketArray<TypeSpecPtr> type_specs_;
+ ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
};
diff --git a/tools/aapt2/Locale.h b/libs/androidfw/include/androidfw/Locale.h
similarity index 94%
rename from tools/aapt2/Locale.h
rename to libs/androidfw/include/androidfw/Locale.h
index 6d8b598..484ed79 100644
--- a/tools/aapt2/Locale.h
+++ b/libs/androidfw/include/androidfw/Locale.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_LOCALE_VALUE_H
-#define AAPT_LOCALE_VALUE_H
+#ifndef ANDROIDFW_LOCALE_VALUE_H
+#define ANDROIDFW_LOCALE_VALUE_H
#include <string>
#include <vector>
@@ -23,7 +23,7 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
-namespace aapt {
+namespace android {
/**
* A convenience class to build and parse locales.
@@ -112,6 +112,6 @@
return compare(o) > 0;
}
-} // namespace aapt
+} // namespace android
-#endif // AAPT_LOCALE_VALUE_H
+#endif // ANDROIDFW_LOCALE_VALUE_H
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
new file mode 100644
index 0000000..8fc3ee2
--- /dev/null
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace util {
+
+struct ProcResult {
+ int status;
+ std::string stdout;
+ std::string stderr;
+};
+
+// Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
+// otherwise a ProcResult containing the external process' exit status and captured stdout and
+// stderr.
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv);
+
+} // namespace util
+} // namespace android
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index e4cd6a8..10d088e 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -19,6 +19,7 @@
#include <cstdlib>
#include <memory>
+#include <vector>
#include "android-base/macros.h"
@@ -47,11 +48,11 @@
constexpr unique_cptr() : ptr_(nullptr) {}
constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
- unique_cptr(unique_cptr&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr; }
+ unique_cptr(unique_cptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
~unique_cptr() { std::free(reinterpret_cast<void*>(ptr_)); }
- inline unique_cptr& operator=(unique_cptr&& o) {
+ inline unique_cptr& operator=(unique_cptr&& o) noexcept {
if (&o == this) {
return *this;
}
@@ -116,6 +117,8 @@
// Converts a UTF-16 string to a UTF-8 string.
std::string Utf16ToUtf8(const StringPiece16& utf16);
+std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 03154d0..c221e3b 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -41,7 +41,8 @@
#include <unistd.h>
#include <time.h>
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
namespace android {
diff --git a/tools/aapt2/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
similarity index 93%
rename from tools/aapt2/ConfigDescription_test.cpp
rename to libs/androidfw/tests/ConfigDescription_test.cpp
index 1f351bf..ce7f805 100644
--- a/tools/aapt2/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -14,18 +14,16 @@
* limitations under the License.
*/
-#include "ConfigDescription.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/StringPiece.h"
+
+#include "android-base/logging.h"
+
+#include "gtest/gtest.h"
#include <string>
-#include "androidfw/StringPiece.h"
-
-#include "SdkConstants.h"
-#include "test/Test.h"
-
-using android::StringPiece;
-
-namespace aapt {
+namespace android {
static ::testing::AssertionResult TestParse(
const StringPiece& input, ConfigDescription* config = nullptr) {
@@ -140,9 +138,13 @@
EXPECT_EQ(std::string("vrheadset-v26"), config.toString().string());
}
-TEST(ConfigDescriptionTest, RangeQualifiersDoNotConflict) {
- using test::ParseConfigOrDie;
+static inline ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
+ ConfigDescription config;
+ CHECK(ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
+ return config;
+}
+TEST(ConfigDescriptionTest, RangeQualifiersDoNotConflict) {
EXPECT_FALSE(ParseConfigOrDie("large").ConflictsWith(ParseConfigOrDie("normal-land")));
EXPECT_FALSE(ParseConfigOrDie("long-hdpi").ConflictsWith(ParseConfigOrDie("xhdpi")));
EXPECT_FALSE(ParseConfigOrDie("sw600dp").ConflictsWith(ParseConfigOrDie("sw700dp")));
@@ -152,4 +154,4 @@
EXPECT_FALSE(ParseConfigOrDie("600x400").ConflictsWith(ParseConfigOrDie("300x200")));
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index cae632d..ffa4836 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -278,4 +278,52 @@
// sizeof(Res_value) might not be backwards compatible.
TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+TEST(LoadedArscTest, ResourceIdentifierIterator) {
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+
+ const auto& loaded_package = packages[0];
+ auto iter = loaded_package->begin();
+ auto end = loaded_package->end();
+
+ ASSERT_NE(end, iter);
+ ASSERT_EQ(0x7f010000u, *iter++);
+ ASSERT_EQ(0x7f010001u, *iter++);
+ ASSERT_EQ(0x7f020000u, *iter++);
+ ASSERT_EQ(0x7f020001u, *iter++);
+ ASSERT_EQ(0x7f030000u, *iter++);
+ ASSERT_EQ(0x7f030001u, *iter++);
+ ASSERT_EQ(0x7f030002u, *iter++); // note: string without default, excluded by aapt2 dump
+ ASSERT_EQ(0x7f040000u, *iter++);
+ ASSERT_EQ(0x7f040001u, *iter++);
+ ASSERT_EQ(0x7f040002u, *iter++);
+ ASSERT_EQ(0x7f040003u, *iter++);
+ ASSERT_EQ(0x7f040004u, *iter++);
+ ASSERT_EQ(0x7f040005u, *iter++);
+ ASSERT_EQ(0x7f040006u, *iter++);
+ ASSERT_EQ(0x7f040007u, *iter++);
+ ASSERT_EQ(0x7f040008u, *iter++);
+ ASSERT_EQ(0x7f040009u, *iter++);
+ ASSERT_EQ(0x7f04000au, *iter++);
+ ASSERT_EQ(0x7f04000bu, *iter++);
+ ASSERT_EQ(0x7f04000cu, *iter++);
+ ASSERT_EQ(0x7f04000du, *iter++);
+ ASSERT_EQ(0x7f050000u, *iter++);
+ ASSERT_EQ(0x7f050001u, *iter++);
+ ASSERT_EQ(0x7f060000u, *iter++);
+ ASSERT_EQ(0x7f070000u, *iter++);
+ ASSERT_EQ(0x7f070001u, *iter++);
+ ASSERT_EQ(0x7f070002u, *iter++);
+ ASSERT_EQ(0x7f070003u, *iter++);
+ ASSERT_EQ(end, iter);
+}
+
} // namespace android
diff --git a/tools/aapt2/Locale_test.cpp b/libs/androidfw/tests/Locale_test.cpp
similarity index 96%
rename from tools/aapt2/Locale_test.cpp
rename to libs/androidfw/tests/Locale_test.cpp
index 68b4cae..6b2ef5f 100644
--- a/tools/aapt2/Locale_test.cpp
+++ b/libs/androidfw/tests/Locale_test.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include "Locale.h"
+#include "androidfw/Locale.h"
+#include "androidfw/Util.h"
#include <string>
#include "gtest/gtest.h"
-#include "util/Util.h"
-
-namespace aapt {
+namespace android {
static ::testing::AssertionResult TestLanguage(const char* input,
const char* lang) {
@@ -93,4 +92,4 @@
EXPECT_TRUE(TestLanguageRegion("fr-rCA", "fr", "CA"));
}
-} // namespace aapt
+} // namespace android
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
new file mode 100644
index 0000000..cf97f87
--- /dev/null
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utility>
+
+#include "androidfw/PosixUtils.h"
+
+#include "TestHelpers.h"
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+namespace android {
+namespace util {
+
+TEST(PosixUtilsTest, AbsolutePathToBinary) {
+ const auto result = ExecuteBinary({"/bin/date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, RelativePathToBinary) {
+ const auto result = ExecuteBinary({"date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, BadParameters) {
+ const auto result = ExecuteBinary({"/bin/date", "--this-parameter-is-not-supported"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_NE(result->status, 0);
+}
+
+TEST(PosixUtilsTest, NoSuchBinary) {
+ const auto result = ExecuteBinary({"/this/binary/does/not/exist"});
+ ASSERT_THAT(result, IsNull());
+}
+
+} // android
+} // util
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index e6d2a6f..f2d50cd 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -146,7 +146,7 @@
frame[FrameInfoIndex::IntendedVsync] + mFrameInterval);
// If we hit the deadline, cool!
- if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) {
+ if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline || totalDuration < mFrameInterval) {
if (isTripleBuffered) {
mData->reportJankType(JankType::kHighInputLatency);
(*mGlobalData)->reportJankType(JankType::kHighInputLatency);
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index 447195d..b09335c 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -18,4 +18,5 @@
name: "com.android.location.provider",
srcs: ["java/**/*.java"],
api_packages: ["com.android.location.provider"],
+ metalava_enabled: false,
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bbc51ce..aec4520 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3932,18 +3932,31 @@
}
/**
- * Indicate Hearing Aid connection state change.
+ * Indicate Hearing Aid connection state change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
* @param device Bluetooth device connected/disconnected
* @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param musicDevice Default get system volume for the connecting device.
+ * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
+ * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * @return a delay in ms that the caller should wait before broadcasting
+ * BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED intent.
* {@hide}
*/
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) {
+ public int setBluetoothHearingAidDeviceConnectionState(
+ BluetoothDevice device, int state, boolean suppressNoisyIntent,
+ int musicDevice) {
final IAudioService service = getService();
+ int delay = 0;
try {
- service.setHearingAidDeviceConnectionState(device, state);
+ delay = service.setBluetoothHearingAidDeviceConnectionState(device,
+ state, suppressNoisyIntent, musicDevice);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ return delay;
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 569db16..abd6411 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -151,8 +151,6 @@
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
- void setHearingAidDeviceConnectionState(in BluetoothDevice device, int state);
-
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
@@ -210,6 +208,9 @@
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+ int setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
+ int state, boolean suppressNoisyIntent, int musicDevice);
+
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 02e1f2f..2eed70f 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -159,8 +159,9 @@
public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
- private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
- private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio";
+ private static final String SYSTEM_SOUNDS_DIR = Environment.getRootDirectory() + "/media/audio";
+ private static final String OEM_SOUNDS_DIR = Environment.getOemDirectory() + "/media/audio";
+ private static final String PRODUCT_SOUNDS_DIR = Environment.getProductDirectory() + "/media/audio";
private static String sLastInternalScanFingerprint;
private static final String[] ID3_GENRES = {
@@ -1192,6 +1193,9 @@
if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
|| path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
|| path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)
+ || path.startsWith(OEM_SOUNDS_DIR + ALARMS_DIR)
+ || path.startsWith(OEM_SOUNDS_DIR + RINGTONES_DIR)
+ || path.startsWith(OEM_SOUNDS_DIR + NOTIFICATIONS_DIR)
|| path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR)
|| path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR)
|| path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
new file mode 100644
index 0000000..bb91d4b
--- /dev/null
+++ b/media/jni/OWNERS
@@ -0,0 +1,2 @@
+# extra for MTP related files
+per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
diff --git a/media/lib/remotedisplay/Android.bp b/media/lib/remotedisplay/Android.bp
index 1e9320d..5f4b930 100644
--- a/media/lib/remotedisplay/Android.bp
+++ b/media/lib/remotedisplay/Android.bp
@@ -14,22 +14,8 @@
// limitations under the License.
//
-droiddoc {
- name: "com.android.media.remotedisplay.stubs-gen-docs",
- srcs: [
- "java/**/*.java",
- ],
- args: " -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
- " -stubpackages com.android.media.remotedisplay " +
- " -nodocs ",
- custom_template: "droiddoc-templates-sdk",
- installable: false,
-}
-
-java_library_static {
- name: "com.android.media.remotedisplay.stubs",
- srcs: [
- ":com.android.media.remotedisplay.stubs-gen-docs",
- ],
- sdk_version: "current",
+java_sdk_library {
+ name: "com.android.media.remotedisplay",
+ srcs: ["java/**/*.java"],
+ api_packages: ["com.android.media.remotedisplay"],
}
diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk
deleted file mode 100644
index e88c0f1..0000000
--- a/media/lib/remotedisplay/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the remotedisplay library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.media.remotedisplay
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ==== com.android.media.remotedisplay.xml lib def ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.media.remotedisplay.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
diff --git a/media/lib/remotedisplay/api/current.txt b/media/lib/remotedisplay/api/current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/remotedisplay/api/current.txt
diff --git a/media/lib/remotedisplay/api/removed.txt b/media/lib/remotedisplay/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/remotedisplay/api/removed.txt
diff --git a/media/lib/remotedisplay/api/system-current.txt b/media/lib/remotedisplay/api/system-current.txt
new file mode 100644
index 0000000..69bbd35
--- /dev/null
+++ b/media/lib/remotedisplay/api/system-current.txt
@@ -0,0 +1,52 @@
+package com.android.media.remotedisplay {
+
+ public class RemoteDisplay {
+ ctor public RemoteDisplay(java.lang.String, java.lang.String);
+ method public java.lang.String getDescription();
+ method public java.lang.String getId();
+ method public java.lang.String getName();
+ method public int getPresentationDisplayId();
+ method public int getStatus();
+ method public int getVolume();
+ method public int getVolumeHandling();
+ method public int getVolumeMax();
+ method public void setDescription(java.lang.String);
+ method public void setName(java.lang.String);
+ method public void setPresentationDisplayId(int);
+ method public void setStatus(int);
+ method public void setVolume(int);
+ method public void setVolumeHandling(int);
+ method public void setVolumeMax(int);
+ field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
+ field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+ field public static final int STATUS_AVAILABLE = 2; // 0x2
+ field public static final int STATUS_CONNECTED = 4; // 0x4
+ field public static final int STATUS_CONNECTING = 3; // 0x3
+ field public static final int STATUS_IN_USE = 1; // 0x1
+ field public static final int STATUS_NOT_AVAILABLE = 0; // 0x0
+ }
+
+ public abstract class RemoteDisplayProvider {
+ ctor public RemoteDisplayProvider(android.content.Context);
+ method public void addDisplay(com.android.media.remotedisplay.RemoteDisplay);
+ method public com.android.media.remotedisplay.RemoteDisplay findRemoteDisplay(java.lang.String);
+ method public android.os.IBinder getBinder();
+ method public final android.content.Context getContext();
+ method public int getDiscoveryMode();
+ method public java.util.Collection<com.android.media.remotedisplay.RemoteDisplay> getDisplays();
+ method public android.app.PendingIntent getSettingsPendingIntent();
+ method public void onAdjustVolume(com.android.media.remotedisplay.RemoteDisplay, int);
+ method public void onConnect(com.android.media.remotedisplay.RemoteDisplay);
+ method public void onDisconnect(com.android.media.remotedisplay.RemoteDisplay);
+ method public void onDiscoveryModeChanged(int);
+ method public void onSetVolume(com.android.media.remotedisplay.RemoteDisplay, int);
+ method public void removeDisplay(com.android.media.remotedisplay.RemoteDisplay);
+ method public void updateDisplay(com.android.media.remotedisplay.RemoteDisplay);
+ field public static final int DISCOVERY_MODE_ACTIVE = 2; // 0x2
+ field public static final int DISCOVERY_MODE_NONE = 0; // 0x0
+ field public static final int DISCOVERY_MODE_PASSIVE = 1; // 0x1
+ field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.remotedisplay.RemoteDisplayProvider";
+ }
+
+}
+
diff --git a/media/lib/remotedisplay/api/system-removed.txt b/media/lib/remotedisplay/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/remotedisplay/api/system-removed.txt
diff --git a/media/lib/remotedisplay/api/test-current.txt b/media/lib/remotedisplay/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/remotedisplay/api/test-current.txt
diff --git a/media/lib/remotedisplay/api/test-removed.txt b/media/lib/remotedisplay/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/remotedisplay/api/test-removed.txt
diff --git a/media/lib/remotedisplay/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml
deleted file mode 100644
index 77a91d2..0000000
--- a/media/lib/remotedisplay/com.android.media.remotedisplay.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<permissions>
- <library name="com.android.media.remotedisplay"
- file="/system/framework/com.android.media.remotedisplay.jar" />
-</permissions>
diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
index dc9dd79..8de414b 100644
--- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
+++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
@@ -16,6 +16,7 @@
package com.android.media.remotedisplay;
+import android.annotation.SystemApi;
import android.media.RemoteDisplayState.RemoteDisplayInfo;
import android.text.TextUtils;
@@ -23,7 +24,10 @@
/**
* Represents a remote display that has been discovered.
+ *
+ * @hide
*/
+@SystemApi
public class RemoteDisplay {
private final RemoteDisplayInfo mMutableInfo;
private RemoteDisplayInfo mImmutableInfo;
diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
index 4d3edb8..7017e44 100644
--- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
+++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -16,6 +16,7 @@
package com.android.media.remotedisplay;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
@@ -88,7 +89,10 @@
* IMPORTANT: This class is effectively a public API for unbundled applications, and
* must remain API stable. See README.txt in the root of this package for more information.
* </p>
+ *
+ * @hide
*/
+@SystemApi
public abstract class RemoteDisplayProvider {
private static final int MSG_SET_CALLBACK = 1;
private static final int MSG_SET_DISCOVERY_MODE = 2;
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 3b25787..8c43683 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -18,4 +18,5 @@
name: "com.android.mediadrm.signer",
srcs: ["java/**/*.java"],
api_packages: ["com.android.mediadrm.signer"],
+ metalava_enabled: false,
}
diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS
new file mode 100644
index 0000000..1928ba8
--- /dev/null
+++ b/media/tests/MtpTests/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+marcone@google.com
+jsharkey@android.com
+jameswei@google.com
+rmojumder@google.com
+
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index fd1212a..774a035 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -130,6 +130,22 @@
mProbeSpec = null;
}
+ mNetworkCallback = new NetworkCallback() {
+ @Override
+ public void onLost(Network lostNetwork) {
+ // If the network disappears while the app is up, exit.
+ if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
+ }
+ };
+ mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkCallback);
+
+ // If the network has disappeared, exit.
+ final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
+ if (networkCapabilities == null) {
+ finishAndRemoveTask();
+ return;
+ }
+
// Also initializes proxy system properties.
mNetwork = mNetwork.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(mNetwork);
@@ -139,24 +155,6 @@
// setContentView initializes the WebView logic which in turn reads the system properties.
setContentView(R.layout.activity_captive_portal_login);
- // Exit app if Network disappears.
- final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
- if (networkCapabilities == null) {
- finishAndRemoveTask();
- return;
- }
- mNetworkCallback = new NetworkCallback() {
- @Override
- public void onLost(Network lostNetwork) {
- if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
- }
- };
- final NetworkRequest.Builder builder = new NetworkRequest.Builder();
- for (int transportType : networkCapabilities.getTransportTypes()) {
- builder.addTransportType(transportType);
- }
- mCm.registerNetworkCallback(builder.build(), mNetworkCallback);
-
getActionBar().setDisplayShowHomeEnabled(false);
getActionBar().setElevation(0); // remove shadow
getActionBar().setTitle(getHeaderTitle());
diff --git a/packages/CarrierDefaultApp/Android.mk b/packages/CarrierDefaultApp/Android.mk
index 5068b3b..df88afd 100644
--- a/packages/CarrierDefaultApp/Android.mk
+++ b/packages/CarrierDefaultApp/Android.mk
@@ -9,8 +9,6 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
-LOCAL_STATIC_JAVA_LIBRARIES := services.net
-
include $(BUILD_PACKAGE)
# This finds and builds the test apk as well, so a single make does both.
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index b1933373..4f67350 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -32,7 +32,6 @@
import android.net.Proxy;
import android.net.TrafficStats;
import android.net.Uri;
-import android.net.dns.ResolvUtil;
import android.net.http.SslError;
import android.os.Bundle;
import android.telephony.CarrierConfigManager;
@@ -159,9 +158,9 @@
private void setNetwork(Network network) {
if (network != null) {
+ network = network.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(network);
- mCm.setProcessDefaultNetworkForHostResolution(
- ResolvUtil.getNetworkWithUseLocalNameserversFlag(network));
+ mCm.setProcessDefaultNetworkForHostResolution(network);
}
mNetwork = network;
}
@@ -242,7 +241,6 @@
private void testForCaptivePortal() {
mTestingThread = new Thread(new Runnable() {
public void run() {
- final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork);
// Give time for captive portal to open.
try {
Thread.sleep(1000);
@@ -253,7 +251,7 @@
int httpResponseCode = 500;
int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
try {
- urlConnection = (HttpURLConnection) network.openConnection(
+ urlConnection = (HttpURLConnection) mNetwork.openConnection(
new URL(mCm.getCaptivePortalServerUrl()));
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index cdaabdc..d0ca04b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -184,7 +184,6 @@
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
- intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index e645adc..03eb0d9 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -67,10 +67,6 @@
LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
@@ -113,10 +109,6 @@
LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/packages/ExtServices/tests/AndroidTest.xml b/packages/ExtServices/tests/AndroidTest.xml
new file mode 100644
index 0000000..c3d32de
--- /dev/null
+++ b/packages/ExtServices/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Tests for ExtServices">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="ExtServicesUnitTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="ExtServicesUnitTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.ext.services.tests.unit" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/packages/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
new file mode 100644
index 0000000..c40a817
--- /dev/null
+++ b/packages/PrintSpooler/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2013 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.
+
+android_app {
+ name: "PrintSpooler",
+
+ resource_dirs: ["res"],
+
+ srcs: [
+ "src/**/*.java",
+ "src/com/android/printspooler/renderer/IPdfRenderer.aidl",
+ "src/com/android/printspooler/renderer/IPdfEditor.aidl",
+ ],
+
+ platform_apis: true,
+
+ jni_libs: ["libprintspooler_jni"],
+ static_libs: [
+ "android-support-v7-recyclerview",
+ "android-support-compat",
+ "android-support-media-compat",
+ "android-support-core-utils",
+ "android-support-core-ui",
+ "android-support-fragment",
+ "android-support-annotations",
+ ],
+}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
deleted file mode 100644
index e356f38..0000000
--- a/packages/PrintSpooler/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_USE_AAPT2 := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
- src/com/android/printspooler/renderer/IPdfRenderer.aidl \
- src/com/android/printspooler/renderer/IPdfEditor.aidl
-
-LOCAL_PACKAGE_NAME := PrintSpooler
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- android-support-v7-recyclerview \
- android-support-compat \
- android-support-media-compat \
- android-support-core-utils \
- android-support-core-ui \
- android-support-fragment
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-annotations
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk
deleted file mode 100644
index 83e00ce..0000000
--- a/packages/PrintSpooler/tests/Android.mk
+++ /dev/null
@@ -1,19 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
new file mode 100644
index 0000000..e88074e
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+android_test {
+ name: "PrintSpoolerOutOfProcessTests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: ["android.test.runner.stubs"],
+ static_libs: [
+ "android-support-test",
+ "ub-uiautomator",
+ "mockito-target-minus-junit4",
+ "print-test-util-lib",
+ ],
+
+ sdk_version: "test_current",
+ test_suites: ["device-tests"],
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
deleted file mode 100644
index 161a600..0000000
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ /dev/null
@@ -1,30 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
-
-LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a46c3e6..76a216d 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1125,4 +1125,7 @@
<!-- time label for event have that happened very recently [CHAR LIMIT=60] -->
<string name="time_unit_just_now">Just now</string>
+
+ <!-- The notice header of Third-party licenses. not translatable -->
+ <string name="notice_header" translatable="false"></string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 541877c..3c58160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -105,7 +105,7 @@
BluetoothProfile.A2DP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index ac5f537..656f23f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -33,7 +33,6 @@
final class A2dpSinkProfile implements LocalBluetoothProfile {
private static final String TAG = "A2dpSinkProfile";
- private static boolean V = true;
private BluetoothA2dpSink mService;
private boolean mIsProfileReady;
@@ -57,7 +56,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothA2dpSink) proxy;
// We just bound to the service, so refresh the UI for any connected A2DP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -76,7 +75,7 @@
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady=false;
}
}
@@ -100,7 +99,7 @@
BluetoothProfile.A2DP_SINK);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -109,7 +108,9 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -117,24 +118,18 @@
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> srcs = getConnectedDevices();
- if (srcs != null) {
- for (BluetoothDevice src : srcs) {
- if (src.equals(device)) {
- // Connect to same device, Ignore it
- Log.d(TAG,"Ignoring Connect");
- return true;
- }
- }
+ if (mService == null) {
+ return false;
}
return mService.connect(device);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
// Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
}
return mService.disconnect(device);
@@ -148,17 +143,23 @@
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -169,7 +170,9 @@
}
boolean isA2dpPlaying() {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
List<BluetoothDevice> srcs = mService.getConnectedDevices();
if (!srcs.isEmpty()) {
if (mService.isA2dpPlaying(srcs.get(0))) {
@@ -211,11 +214,11 @@
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
- mService);
+ mService);
mService = null;
}catch (Throwable t) {
Log.w(TAG, "Error cleaning up A2DP proxy", t);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 0b58c9d..9d8336f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -97,7 +97,6 @@
addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
- addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());
@@ -280,24 +279,6 @@
}
}
- private class DeviceDisappearedHandler implements Handler {
- public void onReceive(Context context, Intent intent,
- BluetoothDevice device) {
- CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
- if (cachedDevice == null) {
- Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
- return;
- }
- if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) {
- synchronized (mCallbacks) {
- for (BluetoothCallback callback : mCallbacks) {
- callback.onDeviceDeleted(cachedDevice);
- }
- }
- }
- }
- }
-
private class NameChangedHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e96c44d..d267ead 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -110,6 +110,10 @@
mHiSyncId = id;
}
+ public boolean isHearingAidDevice() {
+ return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ }
+
/**
* Last time a bt profile auto-connect was attempted.
* If an ACTION_UUID intent comes in within
@@ -144,8 +148,8 @@
void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
if (Utils.D) {
- Log.d(TAG, "onProfileStateChanged: profile " + profile +
- " newProfileState " + newProfileState);
+ Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device=" + mDevice
+ + ", newProfileState " + newProfileState);
}
if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
{
@@ -250,7 +254,7 @@
int preferredProfiles = 0;
for (LocalBluetoothProfile profile : mProfiles) {
- if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+ if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) {
if (profile.isPreferred(mDevice)) {
++preferredProfiles;
connectInt(profile);
@@ -736,7 +740,7 @@
List<LocalBluetoothProfile> connectableProfiles =
new ArrayList<LocalBluetoothProfile>();
for (LocalBluetoothProfile profile : mProfiles) {
- if (profile.isConnectable()) {
+ if (profile.accessProfileEnabled()) {
connectableProfiles.add(profile);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index b360faab..3a56627 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -162,14 +162,14 @@
*/
public synchronized String getHearingAidPairDeviceSummary(CachedBluetoothDevice device) {
String pairDeviceSummary = null;
- if (device.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
- for (CachedBluetoothDevice hearingAidDevice : mHearingAidDevicesNotAddedInCache) {
- if (hearingAidDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
- && hearingAidDevice.getHiSyncId() == device.getHiSyncId()) {
- pairDeviceSummary = hearingAidDevice.getConnectionSummary();
- }
- }
+ CachedBluetoothDevice otherHearingAidDevice =
+ getHearingAidOtherDevice(device, device.getHiSyncId());
+ if (otherHearingAidDevice != null) {
+ pairDeviceSummary = otherHearingAidDevice.getConnectionSummary();
}
+ log("getHearingAidPairDeviceSummary: pairDeviceSummary=" + pairDeviceSummary
+ + ", otherHearingAidDevice=" + otherHearingAidDevice);
+
return pairDeviceSummary;
}
@@ -358,7 +358,7 @@
}
}
- private CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
+ public CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
long hiSyncId) {
if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 7f83860..3bb8450 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -106,7 +106,7 @@
BluetoothProfile.HEADSET);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 1d2fda9..06d60e6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -103,7 +103,7 @@
BluetoothProfile.HEARING_AID);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 03f6afb..4ae9b32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -36,7 +36,6 @@
*/
final class HfpClientProfile implements LocalBluetoothProfile {
private static final String TAG = "HfpClientProfile";
- private static boolean V = false;
private BluetoothHeadsetClient mService;
private boolean mIsProfileReady;
@@ -61,7 +60,7 @@
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothHeadsetClient) proxy;
// We just bound to the service, so refresh the UI for any connected HFP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -82,7 +81,7 @@
@Override
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady=false;
}
}
@@ -108,7 +107,7 @@
}
@Override
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -118,7 +117,9 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -127,23 +128,17 @@
@Override
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> srcs = getConnectedDevices();
- if (srcs != null) {
- for (BluetoothDevice src : srcs) {
- if (src.equals(device)) {
- // Connect to same device, Ignore it
- Log.d(TAG,"Ignoring Connect");
- return true;
- }
- }
+ if (mService == null) {
+ return false;
}
return mService.connect(device);
}
@Override
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
// Downgrade priority as user is disconnecting the headset.
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -161,19 +156,25 @@
@Override
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
@Override
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
@Override
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -219,7 +220,7 @@
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index ca1eea5..1c04e83 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -29,7 +29,7 @@
import java.util.List;
/**
- * HidProfile handles Bluetooth HID profile.
+ * HidDeviceProfile handles Bluetooth HID Device role
*/
public class HidDeviceProfile implements LocalBluetoothProfile {
private static final String TAG = "HidDeviceProfile";
@@ -37,7 +37,6 @@
private static final int ORDINAL = 18;
// HID Device Profile is always preferred.
private static final int PREFERRED_VALUE = -1;
- private static final boolean DEBUG = true;
private final LocalBluetoothAdapter mLocalAdapter;
private final CachedBluetoothDeviceManager mDeviceManager;
@@ -62,9 +61,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) {
- Log.d(TAG,"Bluetooth service connected :-)");
- }
+ Log.d(TAG, "Bluetooth service connected :-), profile:" + profile);
mService = (BluetoothHidDevice) proxy;
// We just bound to the service, so refresh the UI for any connected HID devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -84,9 +81,7 @@
}
public void onServiceDisconnected(int profile) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
@@ -102,7 +97,7 @@
}
@Override
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -113,6 +108,7 @@
@Override
public boolean connect(BluetoothDevice device) {
+ // Don't invoke method in service because settings is not allowed to connect this profile.
return false;
}
@@ -129,11 +125,7 @@
if (mService == null) {
return BluetoothProfile.STATE_DISCONNECTED;
}
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
-
- return !deviceList.isEmpty() && deviceList.contains(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ return mService.getConnectionState(device);
}
@Override
@@ -188,9 +180,7 @@
}
protected void finalize() {
- if (DEBUG) {
- Log.d(TAG, "finalize()");
- }
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_DEVICE,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index dc17e44..1e06481 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -95,7 +95,7 @@
BluetoothProfile.HID_HOST);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 0447f37..4b0ca74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -26,9 +26,9 @@
public interface LocalBluetoothProfile {
/**
- * Returns true if the user can initiate a connection, false otherwise.
+ * Return {@code true} if the user can initiate a connection for this profile in UI.
*/
- boolean isConnectable();
+ boolean accessProfileEnabled();
/**
* Returns true if the user can enable auto connection for this profile.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 08fbbed..88ec1d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -29,6 +29,7 @@
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -101,6 +102,7 @@
private final boolean mUsePbapPce;
private final boolean mUseMapClient;
private HearingAidProfile mHearingAidProfile;
+ private SapProfile mSapProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -196,12 +198,14 @@
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
if (mA2dpSinkProfile == null) {
if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
- mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter,
+ mDeviceManager, this);
addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
}
} else if (mA2dpSinkProfile != null) {
- Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing.");
+ Log.w(TAG, "Warning: A2DP Sink profile was previously added but the "
+ + "UUID is now missing.");
}
// Headset / Handsfree
@@ -217,7 +221,8 @@
BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
}
} else if (mHeadsetProfile != null) {
- Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
+ Log.w(TAG, "Warning: HEADSET profile was previously added but the "
+ + "UUID is now missing.");
}
// Headset HF
@@ -249,7 +254,8 @@
}
} else if (mMapClientProfile != null) {
Log.w(TAG,
- "Warning: MAP Client profile was previously added but the UUID is now missing.");
+ "Warning: MAP Client profile was previously added but the "
+ + "UUID is now missing.");
} else {
Log.d(TAG, "MAP Client Uuid not found.");
}
@@ -266,7 +272,7 @@
Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
}
- //PBAP Client
+ // PBAP Client
if (mUsePbapPce) {
if (mPbapClientProfile == null) {
if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
@@ -280,18 +286,27 @@
"Warning: PBAP Client profile was previously added but the UUID is now missing.");
}
- //Hearing Aid Client
+ // Hearing Aid Client
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
if (mHearingAidProfile == null) {
if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
- mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter,
+ mDeviceManager, this);
addProfile(mHearingAidProfile, HearingAidProfile.NAME,
BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
}
} else if (mHearingAidProfile != null) {
- Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
+ Log.w(TAG, "Warning: Hearing Aid profile was previously added but the "
+ + "UUID is now missing.");
}
+ // SAP
+ if (mSapProfile == null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) {
+ Log.d(TAG, "Adding local SAP profile");
+ mSapProfile = new SapProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mSapProfile, SapProfile.NAME,
+ BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
+ }
mEventManager.registerProfileIntentReceiver();
// There is no local SDP record for HID and Settings app doesn't control PBAP Server.
@@ -363,9 +378,10 @@
Log.i(TAG, "Failed to connect " + mProfile + " device");
}
- if (getHearingAidProfile() != null &&
- mProfile instanceof HearingAidProfile &&
- (newState == BluetoothProfile.STATE_CONNECTED)) {
+ boolean isHearingAidProfile = (getHearingAidProfile() != null) &&
+ (mProfile instanceof HearingAidProfile);
+
+ if (isHearingAidProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
// Check if the HiSyncID has being initialized
if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
@@ -378,10 +394,22 @@
}
}
- mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
- mProfile.getProfileId());
cachedDevice.onProfileStateChanged(mProfile, newState);
cachedDevice.refresh();
+
+ if (isHearingAidProfile) {
+ CachedBluetoothDevice otherDevice =
+ mDeviceManager.getHearingAidOtherDevice(cachedDevice, cachedDevice.getHiSyncId());
+ if (otherDevice != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Refreshing other hearing aid=" + otherDevice
+ + ", newState=" + newState);
+ }
+ otherDevice.refresh();
+ }
+ }
+ mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
+ mProfile.getProfileId());
}
}
@@ -635,6 +663,11 @@
removedProfiles.remove(mHearingAidProfile);
}
+ if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) {
+ profiles.add(mSapProfile);
+ removedProfiles.remove(mSapProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index ad0d8ba..57712e3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -32,11 +32,10 @@
import java.util.List;
/**
- * MapClientProfile handles Bluetooth MAP profile.
+ * MapClientProfile handles the Bluetooth MAP MCE role.
*/
public final class MapClientProfile implements LocalBluetoothProfile {
private static final String TAG = "MapClientProfile";
- private static boolean V = false;
private BluetoothMapClient mService;
private boolean mIsProfileReady;
@@ -61,7 +60,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothMapClient) proxy;
// We just bound to the service, so refresh the UI for any connected MAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -83,14 +82,14 @@
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
}
public boolean isProfileReady() {
- if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+ Log.d(TAG, "isProfileReady(): "+ mIsProfileReady);
return mIsProfileReady;
}
@@ -109,7 +108,7 @@
BluetoothProfile.MAP_CLIENT);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -118,18 +117,16 @@
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> connectedDevices = getConnectedDevices();
- if (connectedDevices != null && connectedDevices.contains(device)) {
- // Connect to same device, Ignore it
- Log.d(TAG,"Ignoring Connect");
- return true;
+ if (mService == null) {
+ return false;
}
return mService.connect(device);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
// Downgrade priority as user is disconnecting.
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -138,23 +135,30 @@
}
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
-
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -165,7 +169,9 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -203,11 +209,11 @@
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP_CLIENT,
- mService);
+ mService);
mService = null;
}catch (Throwable t) {
Log.w(TAG, "Error cleaning up MAP Client proxy", t);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 511c4ce..e59a036 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -107,7 +107,7 @@
BluetoothProfile.MAP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index dfd1622..e1e5dbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -32,7 +32,7 @@
// Order of this profile in device profiles list
private static final int ORDINAL = 2;
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index b18b19b..0d566c7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -80,7 +80,7 @@
BluetoothProfile.PAN);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index bdbfc9d..c83ff35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -34,7 +34,6 @@
public final class PbapClientProfile implements LocalBluetoothProfile {
private static final String TAG = "PbapClientProfile";
- private static boolean V = false;
private BluetoothPbapClient mService;
private boolean mIsProfileReady;
@@ -57,9 +56,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) {
- Log.d(TAG,"Bluetooth service connected");
- }
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothPbapClient) proxy;
// We just bound to the service, so refresh the UI for any connected PBAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -78,9 +75,7 @@
}
public void onServiceDisconnected(int profile) {
- if (V) {
- Log.d(TAG,"Bluetooth service disconnected");
- }
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
@@ -115,7 +110,7 @@
BluetoothProfile.PBAP_CLIENT);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -134,31 +129,16 @@
}
public boolean connect(BluetoothDevice device) {
- if (V) {
- Log.d(TAG,"PBAPClientProfile got connect request");
- }
+ Log.d(TAG,"PBAPClientProfile got connect request");
if (mService == null) {
return false;
}
- List<BluetoothDevice> srcs = getConnectedDevices();
- if (srcs != null) {
- for (BluetoothDevice src : srcs) {
- if (src.equals(device)) {
- // Connect to same device, Ignore it
- Log.d(TAG,"Ignoring Connect");
- return true;
- }
- }
- }
Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
-
return mService.connect(device);
}
public boolean disconnect(BluetoothDevice device) {
- if (V) {
- Log.d(TAG,"PBAPClientProfile got disconnect request");
- }
+ Log.d(TAG,"PBAPClientProfile got disconnect request");
if (mService == null) {
return false;
}
@@ -221,9 +201,7 @@
}
protected void finalize() {
- if (V) {
- Log.d(TAG, "finalize()");
- }
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index e9d8cb5..adef0841 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -80,7 +80,7 @@
BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 2c455d5f..e83c62d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -36,7 +36,6 @@
*/
final class SapProfile implements LocalBluetoothProfile {
private static final String TAG = "SapProfile";
- private static boolean V = true;
private BluetoothSap mService;
private boolean mIsProfileReady;
@@ -59,7 +58,7 @@
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothSap) proxy;
// We just bound to the service, so refresh the UI for any connected SAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,7 +80,7 @@
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
@@ -106,7 +105,7 @@
BluetoothProfile.SAP);
}
- public boolean isConnectable() {
+ public boolean accessProfileEnabled() {
return true;
}
@@ -115,50 +114,47 @@
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> sinks = mService.getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
+ if (mService == null) {
+ return false;
}
return mService.connect(device);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- return mService.disconnect(device);
- } else {
+ if (mService == null) {
return false;
}
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
}
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
-
- return !deviceList.isEmpty() && deviceList.get(0).equals(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -169,7 +165,9 @@
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -207,11 +205,11 @@
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP,
- mService);
+ mService);
mService = null;
}catch (Throwable t) {
Log.w(TAG, "Error cleaning up SAP proxy", t);
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
index 42306f6..9870b3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
@@ -107,12 +107,13 @@
mXmlFiles = xmlFiles;
}
- public static boolean generateHtml(List<File> xmlFiles, File outputFile) {
+ public static boolean generateHtml(List<File> xmlFiles, File outputFile,
+ String noticeHeader) {
LicenseHtmlGeneratorFromXml genertor = new LicenseHtmlGeneratorFromXml(xmlFiles);
- return genertor.generateHtml(outputFile);
+ return genertor.generateHtml(outputFile, noticeHeader);
}
- private boolean generateHtml(File outputFile) {
+ private boolean generateHtml(File outputFile, String noticeHeader) {
for (File xmlFile : mXmlFiles) {
parse(xmlFile);
}
@@ -125,7 +126,8 @@
try {
writer = new PrintWriter(outputFile);
- generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer);
+ generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer,
+ noticeHeader);
writer.flush();
writer.close();
@@ -239,13 +241,18 @@
@VisibleForTesting
static void generateHtml(Map<String, String> fileNameToContentIdMap,
- Map<String, String> contentIdToFileContentMap, PrintWriter writer) {
+ Map<String, String> contentIdToFileContentMap, PrintWriter writer,
+ String noticeHeader) {
List<String> fileNameList = new ArrayList();
fileNameList.addAll(fileNameToContentIdMap.keySet());
Collections.sort(fileNameList);
writer.println(HTML_HEAD_STRING);
+ if (!TextUtils.isEmpty(noticeHeader)) {
+ writer.println(noticeHeader);
+ }
+
int count = 0;
Map<String, Integer> contentIdToOrderMap = new HashMap();
List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList();
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
index 2aaea65..8b562f70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
@@ -21,6 +21,7 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settingslib.R;
import com.android.settingslib.utils.AsyncLoader;
import java.io.File;
@@ -108,6 +109,7 @@
@VisibleForTesting
boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) {
- return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile);
+ return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile,
+ mContext.getString(R.string.notice_header));
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
new file mode 100644
index 0000000..d38a2d0
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothA2dpSink;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class A2dpSinkProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothA2dpSink mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private A2dpSinkProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.A2DP_SINK));
+
+ mProfile = new A2dpSinkProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothA2dpSink() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothA2dpSink() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 6d6a132..a3d10a2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -828,4 +828,20 @@
assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
}
+
+ /**
+ * Test to verify getHearingAidOtherDevice() for hearing aid devices with same HiSyncId.
+ */
+ @Test
+ public void testGetHearingAidOtherDevice_bothHearingAidsPaired_returnsOtherDevice() {
+ mCachedDevice1.setHiSyncId(HISYNCID1);
+ mCachedDevice2.setHiSyncId(HISYNCID1);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+ mCachedDeviceManager.mHearingAidDevicesNotAddedInCache.add(mCachedDevice2);
+ doAnswer((invocation) -> DEVICE_SUMMARY_1).when(mCachedDevice1).getConnectionSummary();
+ doAnswer((invocation) -> DEVICE_SUMMARY_2).when(mCachedDevice2).getConnectionSummary();
+
+ assertThat(mCachedDeviceManager.getHearingAidOtherDevice(mCachedDevice1, HISYNCID1))
+ .isEqualTo(mCachedDevice2);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 927a94f..16a292b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -28,6 +28,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
@@ -572,4 +573,16 @@
assertThat(mCachedDevice.isHfpDevice()).isFalse();
}
+
+ @Test
+ public void testIsHearingAidDevice_isHearingAidDevice() {
+ mCachedDevice.setHiSyncId(0x1234);
+ assertThat(mCachedDevice.isHearingAidDevice()).isTrue();
+ }
+
+ @Test
+ public void testIsHearingAidDevice_isNotHearingAidDevice() {
+ mCachedDevice.setHiSyncId(BluetoothHearingAid.HI_SYNC_ID_INVALID);
+ assertThat(mCachedDevice.isHearingAidDevice()).isFalse();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
new file mode 100644
index 0000000..7b467d6
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class HfpClientProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothHeadsetClient mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private HfpClientProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.HEADSET_CLIENT));
+
+ mProfile = new HfpClientProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothHeadsetClient() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothHeadsetClient() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
new file mode 100644
index 0000000..354d926
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class HidDeviceProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothHidDevice mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private HidDeviceProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.HID_DEVICE));
+
+ mProfile = new HidDeviceProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE, mService);
+ }
+
+ @Test
+ public void connect_shouldReturnFalse() {
+ assertThat(mProfile.connect(mBluetoothDevice)).isFalse();
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothHidDevice() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index ca997bf8..17af429 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -51,6 +52,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(resourceDir = "../../res")
public class LocalBluetoothProfileManagerTest {
+ private final static long HI_SYNC_ID = 0x1234;
@Mock
private CachedBluetoothDeviceManager mDeviceManager;
@Mock
@@ -61,6 +63,8 @@
private BluetoothDevice mDevice;
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private CachedBluetoothDevice mHearingAidOtherDevice;
private Context mContext;
private LocalBluetoothProfileManager mProfileManager;
@@ -199,6 +203,32 @@
}
/**
+ * Verify BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
+ * refresh both sides devices.
+ */
+ @Test
+ public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldRefreshBothSides() {
+ ArrayList<Integer> supportProfiles = new ArrayList<>();
+ supportProfiles.add(BluetoothProfile.HEARING_AID);
+ when(mAdapter.getSupportedProfiles()).thenReturn(supportProfiles);
+ when(mCachedBluetoothDevice.getHiSyncId()).thenReturn(HI_SYNC_ID);
+ when(mDeviceManager.getHearingAidOtherDevice(mCachedBluetoothDevice, HI_SYNC_ID))
+ .thenReturn(mHearingAidOtherDevice);
+
+ mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+ mEventManager);
+ mIntent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+ mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+ mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mCachedBluetoothDevice).refresh();
+ verify(mHearingAidOtherDevice).refresh();
+ }
+
+ /**
* Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
* profile connection state changed callback
*/
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
new file mode 100644
index 0000000..97c9f18
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class MapClientProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothMapClient mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private MapClientProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.MAP_CLIENT));
+
+ mProfile = new MapClientProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.MAP_CLIENT, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothMapClient() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothMapClient() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
new file mode 100644
index 0000000..45b52b2
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class PbapClientProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothPbapClient mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private PbapClientProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.PBAP_CLIENT));
+
+ mProfile = new PbapClientProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothPbapClient() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothPbapClient() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
new file mode 100644
index 0000000..6ff3e70
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSap;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class SapProfileTest {
+
+ @Mock
+ private LocalBluetoothAdapter mAdapter;
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothSap mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private SapProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class),
+ any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.SAP));
+
+ mProfile = new SapProfile(RuntimeEnvironment.application, mAdapter,
+ mDeviceManager, mProfileManager);
+ mServiceListener.onServiceConnected(BluetoothProfile.SAP, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothSap() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothSap() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 96b2a14..b00476b2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -50,7 +50,7 @@
+ "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n"
+ "</licenses2>";
- private static final String EXPECTED_HTML_STRING =
+ private static final String HTML_HEAD_STRING =
"<html><head>\n"
+ "<style type=\"text/css\">\n"
+ "body { padding: 0; font-family: sans-serif; }\n"
@@ -63,8 +63,12 @@
+ "</head>"
+ "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"
+ "<div class=\"toc\">\n"
- + "<ul>\n"
- + "<li><a href=\"#id0\">/file0</a></li>\n"
+ + "<ul>\n";
+
+ private static final String HTML_CUSTOM_HEADING = "Custom heading";
+
+ private static final String HTML_BODY_STRING =
+ "<li><a href=\"#id0\">/file0</a></li>\n"
+ "<li><a href=\"#id0\">/file1</a></li>\n"
+ "</ul>\n"
+ "</div><!-- table of contents -->\n"
@@ -81,6 +85,11 @@
+ "</td></tr><!-- same-license -->\n"
+ "</table></body></html>\n";
+ private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING;
+
+ private static final String EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING =
+ HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING;
+
@Test
public void testParseValidXmlStream() throws XmlPullParserException, IOException {
Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
@@ -117,7 +126,23 @@
StringWriter output = new StringWriter();
LicenseHtmlGeneratorFromXml.generateHtml(
- fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output));
+ fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), "");
assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING);
}
+
+ @Test
+ public void testGenerateHtmlWithCustomHeading() {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ fileNameToContentIdMap.put("/file0", "0");
+ fileNameToContentIdMap.put("/file1", "0");
+ contentIdToFileContentMap.put("0", "license content #0");
+
+ StringWriter output = new StringWriter();
+ LicenseHtmlGeneratorFromXml.generateHtml(
+ fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output),
+ HTML_CUSTOM_HEADING);
+ assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING);
+ }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8a5cb4a..abce8cf 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
@@ -54,6 +55,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
<!-- Development tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 4fc190d..2530abc 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -16,6 +16,8 @@
package com.android.shell;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.shell.BugreportPrefs.STATE_HIDE;
@@ -42,6 +44,7 @@
import libcore.io.Streams;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
import com.android.internal.logging.MetricsLogger;
@@ -232,9 +235,11 @@
*/
private boolean mTakingScreenshot;
+ @GuardedBy("sNotificationBundle")
private static final Bundle sNotificationBundle = new Bundle();
private boolean mIsWatch;
+ private boolean mIsTv;
private int mLastProgressPercent;
@@ -255,6 +260,9 @@
final Configuration conf = mContext.getResources().getConfiguration();
mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) ==
Configuration.UI_MODE_TYPE_WATCH;
+ PackageManager packageManager = getPackageManager();
+ mIsTv = packageManager.hasSystemFeature(FEATURE_LEANBACK)
+ || packageManager.hasSystemFeature(FEATURE_TELEVISION);
NotificationManager nm = NotificationManager.from(mContext);
nm.createNotificationChannel(
new NotificationChannel(NOTIFICATION_CHANNEL_ID,
@@ -500,8 +508,8 @@
.setProgress(info.max, info.progress, false)
.setOngoing(true);
- // Wear bugreport doesn't need the bug info dialog, screenshot and cancel action.
- if (!mIsWatch) {
+ // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action.
+ if (!(mIsWatch || mIsTv)) {
final Action cancelAction = new Action.Builder(null, mContext.getString(
com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
@@ -1053,10 +1061,12 @@
}
private static Notification.Builder newBaseNotification(Context context) {
- if (sNotificationBundle.isEmpty()) {
- // Rename notifcations from "Shell" to "Android System"
- sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- context.getString(com.android.internal.R.string.android_system_label));
+ synchronized (sNotificationBundle) {
+ if (sNotificationBundle.isEmpty()) {
+ // Rename notifcations from "Shell" to "Android System"
+ sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label));
+ }
}
return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
.addExtras(sNotificationBundle)
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 0734e0d..4fbc226 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.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 @@
}
@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 c4f75e9..015e30a 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/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436de..d033057 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
android:paddingEnd="@dimen/status_bar_padding_end"
android:orientation="horizontal"
>
- <ViewStub
- android:id="@+id/operator_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/operator_name" />
<FrameLayout
android:layout_height="match_parent"
android:layout_width="0dp"
@@ -70,6 +65,12 @@
android:layout_width="match_parent"
android:clipChildren="false"
>
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
+
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index cd831d1..0c498bb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -24,8 +24,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import sun.misc.Resource;
-
public class NavigationBarCompat {
/**
* Touch slopes and thresholds for quick step operations. Drag slop is the point where the
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 9435589..f4f2ebc 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -38,6 +38,7 @@
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.systemui.util.EmergencyDialerConstants;
/**
* This class implements a smart emergency button that updates itself based
@@ -47,11 +48,13 @@
*/
public class EmergencyButton extends Button {
private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
- .setAction("com.android.phone.EmergencyDialer.DIAL")
+ .setAction(EmergencyDialerConstants.ACTION_DIAL)
.setPackage("com.android.phone")
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+ EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
private static final String LOG_TAG = "EmergencyButton";
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9e4810c..35abb0a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -342,12 +342,11 @@
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode != SecurityMode.None
- || !mLockPatternUtils.isLockScreenDisabled(
+ if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser())) {
- showSecurityScreen(securityMode);
- } else {
finish = true;
+ } else {
+ showSecurityScreen(securityMode);
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 8320d32..f4cdbac 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -55,6 +55,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -89,6 +90,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
import java.util.ArrayList;
@@ -317,8 +319,8 @@
ArraySet<String> addedKeys = new ArraySet<String>();
mHasLogoutButton = false;
mHasLockdownButton = false;
- mSeparatedEmergencyButtonEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
+ mSeparatedEmergencyButtonEnabled = FeatureFlagUtils
+ .isEnabled(mContext, FeatureFlagUtils.EMERGENCY_DIAL_SHORTCUTS);
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -448,9 +450,6 @@
}
private class EmergencyDialerAction extends SinglePressAction {
- private static final String ACTION_EMERGENCY_DIALER_DIAL =
- "com.android.phone.EmergencyDialer.DIAL";
-
private EmergencyDialerAction() {
super(R.drawable.ic_faster_emergency,
R.string.global_action_emergency);
@@ -458,8 +457,10 @@
@Override
public void onPress() {
- Intent intent = new Intent(ACTION_EMERGENCY_DIALER_DIAL);
+ Intent intent = new Intent(EmergencyDialerConstants.ACTION_DIAL);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+ EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 409a783..118f1e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -47,6 +47,7 @@
private final NotificationStackScrollLayout mStackScroller;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mClockView;
+ private final View mOperatorNameView;
private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelView mPanelView;
private final Consumer<ExpandableNotificationRow>
@@ -61,8 +62,10 @@
private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> updatePanelTranslation();
+ private boolean mAnimationsEnabled = true;
Point mPoint;
+
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
@@ -71,7 +74,8 @@
statusbarView.findViewById(R.id.heads_up_status_bar_view),
statusbarView.findViewById(R.id.notification_stack_scroller),
statusbarView.findViewById(R.id.notification_panel),
- statusbarView.findViewById(R.id.clock));
+ statusbarView.findViewById(R.id.clock),
+ statusbarView.findViewById(R.id.operator_name_frame));
}
@VisibleForTesting
@@ -81,7 +85,8 @@
HeadsUpStatusBarView headsUpStatusBarView,
NotificationStackScrollLayout stackScroller,
NotificationPanelView panelView,
- View clockView) {
+ View clockView,
+ View operatorNameView) {
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(this);
@@ -97,6 +102,7 @@
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
+ mOperatorNameView = operatorNameView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mDarkIconDispatcher.addDarkReceiver(this);
}
@@ -205,20 +211,52 @@
mShown = isShown;
if (isShown) {
mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
- CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+ show(mHeadsUpStatusBarView);
+ hide(mClockView, View.INVISIBLE);
+ if (mOperatorNameView != null) {
+ hide(mOperatorNameView, View.INVISIBLE);
+ }
} else {
- CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+ show(mClockView);
+ if (mOperatorNameView != null) {
+ show(mOperatorNameView);
+ }
+ hide(mHeadsUpStatusBarView, View.GONE);
}
}
}
+ /**
+ * Hides the view and sets the state to endState when finished.
+ *
+ * @param view The view to hide.
+ * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+ * @see View#setVisibility(int)
+ *
+ */
+ private void hide(View view, int endState) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+ 0 /* delay */, () -> view.setVisibility(endState));
+ } else {
+ view.setVisibility(endState);
+ }
+ }
+
+ private void show(View view) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ } else {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @VisibleForTesting
+ void setAnimationsEnabled(boolean enabled) {
+ mAnimationsEnabled = enabled;
+ }
+
@VisibleForTesting
public boolean isShown() {
return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 2031b27..1fefa18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -53,6 +53,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final Object mCallbacksLock = new Object();
private final Context mContext;
private final GlobalSetting mModeSetting;
private final GlobalSetting mConfigSetting;
@@ -113,16 +114,20 @@
@Override
public void addCallback(Callback callback) {
- if (callback == null) {
- Slog.e(TAG, "Attempted to add a null callback.");
- return;
+ synchronized (mCallbacksLock) {
+ if (callback == null) {
+ Slog.e(TAG, "Attempted to add a null callback.");
+ return;
+ }
+ mCallbacks.add(callback);
}
- mCallbacks.add(callback);
}
@Override
public void removeCallback(Callback callback) {
- mCallbacks.remove(callback);
+ synchronized (mCallbacksLock) {
+ mCallbacks.remove(callback);
+ }
}
@Override
@@ -186,28 +191,40 @@
}
private void fireNextAlarmChanged() {
- Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged());
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged());
+ }
}
private void fireEffectsSuppressorChanged() {
- Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged());
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged());
+ }
}
private void fireZenChanged(int zen) {
- Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen));
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen));
+ }
}
private void fireZenAvailableChanged(boolean available) {
- Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available));
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available));
+ }
}
private void fireManualRuleChanged(ZenRule rule) {
- Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule));
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule));
+ }
}
@VisibleForTesting
protected void fireConfigChanged(ZenModeConfig config) {
- Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config));
+ synchronized (mCallbacksLock) {
+ Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config));
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
index af99236..e85dee8 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
@@ -51,7 +51,9 @@
public void onTuningChanged(String key, String newValue) {
int dimen = mDefaultSize;
if (newValue != null) {
- dimen = (int) (Integer.parseInt(newValue) * mDensity);
+ try {
+ dimen = (int) (Integer.parseInt(newValue) * mDensity);
+ } catch (NumberFormatException ex) {}
}
int left = mView.isLayoutRtl() ? FLAG_END : FLAG_START;
int right = mView.isLayoutRtl() ? FLAG_START : FLAG_END;
diff --git a/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
new file mode 100644
index 0000000..d101ccb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util;
+
+/**
+ * Constants defined and used in emergency dialer.
+ * Please keep these constants being consistent with those in com.android.phone.EmergencyDialer.
+ */
+public class EmergencyDialerConstants {
+ // Intent action for emergency dialer activity.
+ public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
+ /**
+ * Extra included in {@link #ACTION_DIAL} to indicate the entry type that user starts
+ * the emergency dialer.
+ */
+ public static final String EXTRA_ENTRY_TYPE =
+ "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE";
+
+ // Indicating the entrance to emergency dialer
+ public static final int ENTRY_TYPE_UNKNOWN = 0;
+ public static final int ENTRY_TYPE_LOCKSCREEN_BUTTON = 1;
+ public static final int ENTRY_TYPE_POWER_MENU = 2;
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 537bfd4..3c5c0b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -61,6 +61,7 @@
private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
private HeadsUpManagerPhone mHeadsUpManager;
+ private View mOperatorNameView;
@Before
public void setUp() throws Exception {
@@ -70,13 +71,15 @@
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+ mOperatorNameView = new View(mContext);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
mHeadsUpManager,
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
- new View(mContext));
+ new View(mContext),
+ mOperatorNameView);
mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
}
@@ -123,6 +126,22 @@
}
@Test
+ public void testOperatorNameViewUpdated() {
+ mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+ }
+
+ @Test
public void testDestroy() {
reset(mHeadsUpManager);
reset(mDarkIconDispatcher);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index cae15ba..8cfbda2 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -4,6 +4,7 @@
aidl: {
include_dirs: [
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"system/core/storaged/binder",
"system/netd/server/binder",
"system/vold/binder",
@@ -11,6 +12,7 @@
},
srcs: [
"java/**/*.java",
+ ":dumpstate_aidl",
":netd_aidl",
":netd_metrics_aidl",
":installd_aidl",
@@ -43,6 +45,7 @@
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.0-java",
+ "netd_aidl_interface-java",
],
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 99e0056..49de4b1 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -53,12 +53,16 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.StatsLog;
@@ -386,6 +390,15 @@
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
+ // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
+ boolean isHearingAidEnabled;
+ String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
+ if (!TextUtils.isEmpty(value)) {
+ isHearingAidEnabled = Boolean.parseBoolean(value);
+ Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
+ FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
+ }
+
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7602090..b750d79 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -49,10 +52,12 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
import android.net.IIpConnectivityMetrics;
+import android.net.INetd;
import android.net.INetdEventCallback;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
@@ -75,7 +80,6 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
-import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.UidRange;
@@ -83,7 +87,9 @@
import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
+import android.net.netlink.InetDiagMessage;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.NetdService;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -153,7 +159,6 @@
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.Tethering;
@@ -256,7 +261,8 @@
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
- private INetworkManagementService mNetd;
+ private INetworkManagementService mNMS;
+ private INetd mNetd;
private INetworkStatsService mStatsService;
private INetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
@@ -387,9 +393,9 @@
private static final int EVENT_PROMPT_UNVALIDATED = 29;
/**
- * used internally to (re)configure mobile data always-on settings.
+ * used internally to (re)configure always-on networks.
*/
- private static final int EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON = 30;
+ private static final int EVENT_CONFIGURE_ALWAYS_ON_NETWORKS = 30;
/**
* used to add a network listener with a pending intent
@@ -745,6 +751,12 @@
mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
+ // The default WiFi request is a background request so that apps using WiFi are
+ // migrated to a better network (typically ethernet) when one comes up, instead
+ // of staying on WiFi forever.
+ mDefaultWifiRequest = createDefaultInternetRequestForTransport(
+ NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
+
mHandlerThread = new HandlerThread("ConnectivityServiceThread");
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
@@ -756,7 +768,7 @@
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
mContext = checkNotNull(context, "missing Context");
- mNetd = checkNotNull(netManager, "missing INetworkManagementService");
+ mNMS = checkNotNull(netManager, "missing INetworkManagementService");
mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
mPolicyManagerInternal = checkNotNull(
@@ -764,6 +776,7 @@
"missing NetworkPolicyManagerInternal");
mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
+ mNetd = NetdService.getInstance();
mKeyStore = KeyStore.getInstance();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -846,7 +859,7 @@
mTethering = makeTethering();
- mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+ mPermissionMonitor = new PermissionMonitor(mContext, mNMS);
//set up the listener for user state for creating user VPNs
IntentFilter intentFilter = new IntentFilter();
@@ -861,8 +874,8 @@
new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
try {
- mNetd.registerObserver(mTethering);
- mNetd.registerObserver(mDataActivityObserver);
+ mNMS.registerObserver(mTethering);
+ mNMS.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
}
@@ -893,7 +906,7 @@
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
- mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
+ mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
registerPrivateDnsSettingsCallbacks();
}
@@ -909,7 +922,7 @@
return mDefaultRequest;
}
};
- return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
+ return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
}
@@ -941,8 +954,8 @@
// 2. Give FakeSettingsProvider an alternative notification mechanism and have the test use it
// by subclassing SettingsObserver.
@VisibleForTesting
- void updateMobileDataAlwaysOn() {
- mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
+ void updateAlwaysOnNetworks() {
+ mHandler.sendEmptyMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}
// See FakeSettingsProvider comment above.
@@ -951,22 +964,30 @@
mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
}
- private void handleMobileDataAlwaysOn() {
+ private void handleAlwaysOnNetworkRequest(
+ NetworkRequest networkRequest, String settingName, boolean defaultValue) {
final boolean enable = toBool(Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1));
- final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null);
+ mContext.getContentResolver(), settingName, encodeBool(defaultValue)));
+ final boolean isEnabled = (mNetworkRequests.get(networkRequest) != null);
if (enable == isEnabled) {
return; // Nothing to do.
}
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- null, mDefaultMobileDataRequest, new Binder()));
+ null, networkRequest, new Binder()));
} else {
- handleReleaseNetworkRequest(mDefaultMobileDataRequest, Process.SYSTEM_UID);
+ handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID);
}
}
+ private void handleConfigureAlwaysOnNetworks() {
+ handleAlwaysOnNetworkRequest(
+ mDefaultMobileDataRequest,Settings.Global.MOBILE_DATA_ALWAYS_ON, true);
+ handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED,
+ false);
+ }
+
private void registerSettingsCallbacks() {
// Watch for global HTTP proxy changes.
mSettingsObserver.observe(
@@ -976,7 +997,12 @@
// Watch for whether or not to keep mobile data always on.
mSettingsObserver.observe(
Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
- EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
+ EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
+
+ // Watch for whether or not to keep wifi always on.
+ mSettingsObserver.observe(
+ Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED),
+ EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}
private void registerPrivateDnsSettingsCallbacks() {
@@ -1473,6 +1499,20 @@
};
/**
+ * Ensures that the system cannot call a particular method.
+ */
+ private boolean disallowedBecauseSystemCaller() {
+ // TODO: start throwing a SecurityException when GnssLocationProvider stops calling
+ // requestRouteToHost.
+ if (isSystem(Binder.getCallingUid())) {
+ log("This method exists only for app backwards compatibility"
+ + " and must not be called by system services.");
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface.
* @param networkType the type of the network over which traffic to the
@@ -1483,6 +1523,9 @@
*/
@Override
public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
+ if (disallowedBecauseSystemCaller()) {
+ return false;
+ }
enforceChangePermission();
if (mProtectedNetworks.contains(networkType)) {
enforceConnectivityInternalPermission();
@@ -1560,7 +1603,7 @@
if (DBG) log("Adding legacy route " + bestRoute +
" for UID/PID " + uid + "/" + Binder.getCallingPid());
try {
- mNetd.addLegacyRouteForNetId(netId, bestRoute, uid);
+ mNMS.addLegacyRouteForNetId(netId, bestRoute, uid);
} catch (Exception e) {
// never crash - catch them all
if (DBG) loge("Exception trying to add a route: " + e);
@@ -1636,6 +1679,16 @@
"ConnectivityService");
}
+ private void enforceAnyPermissionOf(String... permissions) {
+ for (String permission : permissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return;
+ }
+ }
+ throw new SecurityException(
+ "Requires one of the following permissions: " + String.join(", ", permissions) + ".");
+ }
+
private void enforceInternetPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERNET,
@@ -1680,6 +1733,18 @@
"ConnectivityService");
}
+ private void enforceNetworkStackSettingsOrSetup() {
+ enforceAnyPermissionOf(
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK);
+ }
+
+ private boolean checkNetworkStackPermission() {
+ return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_STACK);
+ }
+
private void enforceConnectivityRestrictedNetworksPermission() {
try {
mContext.enforceCallingOrSelfPermission(
@@ -1750,7 +1815,8 @@
private void sendStickyBroadcast(Intent intent) {
synchronized (this) {
- if (!mSystemReady) {
+ if (!mSystemReady
+ && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mInitialBroadcast = new Intent(intent);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1789,7 +1855,7 @@
}
void systemReady() {
- loadGlobalProxy();
+ mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
synchronized (this) {
@@ -1799,15 +1865,13 @@
mInitialBroadcast = null;
}
}
- // load the global proxy at startup
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
// Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
// for user to unlock device too.
updateLockdownVpn();
- // Configure whether mobile data is always on.
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
+ // Create network requests for always-on networks.
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
@@ -1845,7 +1909,7 @@
if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
try {
- mNetd.addIdleTimer(iface, timeout, type);
+ mNMS.addIdleTimer(iface, timeout, type);
} catch (Exception e) {
// You shall not crash!
loge("Exception in setupDataActivityTracking " + e);
@@ -1864,7 +1928,7 @@
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
try {
// the call fails silently if no idle timer setup for this interface
- mNetd.removeIdleTimer(iface);
+ mNMS.removeIdleTimer(iface);
} catch (Exception e) {
loge("Exception in removeDataActivityTracking " + e);
}
@@ -1872,6 +1936,18 @@
}
/**
+ * Update data activity tracking when network state is updated.
+ */
+ private void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+ NetworkAgentInfo oldNetwork) {
+ if (newNetwork != null) {
+ setupDataActivityTracking(newNetwork);
+ }
+ if (oldNetwork != null) {
+ removeDataActivityTracking(oldNetwork);
+ }
+ }
+ /**
* Reads the network specific MTU size from resources.
* and set it on it's iface.
*/
@@ -1899,7 +1975,7 @@
try {
if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
- mNetd.setMtu(iface, mtu);
+ mNMS.setMtu(iface, mtu);
} catch (Exception e) {
Slog.e(TAG, "exception in setMtu()" + e);
}
@@ -2553,7 +2629,7 @@
}
nai.clearLingerState();
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
- removeDataActivityTracking(nai);
+ updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.name());
}
@@ -2573,7 +2649,7 @@
// NetworkFactories, so network traffic isn't interrupted for an unnecessarily
// long time.
try {
- mNetd.removeNetwork(nai.network.netId);
+ mNMS.removeNetwork(nai.network.netId);
} catch (Exception e) {
loge("Exception removing network: " + e);
}
@@ -2771,20 +2847,6 @@
}
}
- // TODO: remove this code once we know that the Slog.wtf is never hit.
- //
- // Find all networks that are satisfying this request and remove the request
- // from their request lists.
- // TODO - it's my understanding that for a request there is only a single
- // network satisfying it, so this loop is wasteful
- for (NetworkAgentInfo otherNai : mNetworkAgentInfos.values()) {
- if (otherNai.isSatisfyingRequest(nri.request.requestId) && otherNai != nai) {
- Slog.wtf(TAG, "Request " + nri.request + " satisfied by " +
- otherNai.name() + ", but mNetworkAgentInfos says " +
- (nai != null ? nai.name() : "null"));
- }
- }
-
// Maintain the illusion. When this request arrived, we might have pretended
// that a network connected to serve it, even though the network was already
// connected. Now that this request has gone away, we might have to pretend
@@ -3043,7 +3105,7 @@
break;
}
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
- handleDeprecatedGlobalHttpProxy();
+ mProxyTracker.loadDeprecatedGlobalHttpProxy();
break;
}
case EVENT_PROXY_HAS_CHANGED: {
@@ -3098,8 +3160,8 @@
handlePromptUnvalidated((Network) msg.obj);
break;
}
- case EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON: {
- handleMobileDataAlwaysOn();
+ case EVENT_CONFIGURE_ALWAYS_ON_NETWORKS: {
+ handleConfigureAlwaysOnNetworks();
break;
}
// Sent by KeepaliveTracker to process an app request on the state machine thread.
@@ -3409,31 +3471,6 @@
mProxyTracker.setGlobalProxy(proxyProperties);
}
- private void loadGlobalProxy() {
- ContentResolver res = mContext.getContentResolver();
- String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
- int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
- String exclList = Settings.Global.getString(res,
- Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
- if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
- ProxyInfo proxyProperties;
- if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyInfo(pacFileUrl);
- } else {
- proxyProperties = new ProxyInfo(host, port, exclList);
- }
- if (!proxyProperties.isValid()) {
- if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
- return;
- }
-
- synchronized (mProxyTracker.mProxyLock) {
- mProxyTracker.mGlobalProxy = proxyProperties;
- }
- }
- }
-
@Override
@Nullable
public ProxyInfo getGlobalProxy() {
@@ -3458,30 +3495,7 @@
ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.getDefaultProxy());
- }
- }
-
- private void handleDeprecatedGlobalHttpProxy() {
- final String proxy = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.HTTP_PROXY);
- if (!TextUtils.isEmpty(proxy)) {
- String data[] = proxy.split(":");
- if (data.length == 0) {
- return;
- }
-
- final String proxyHost = data[0];
- int proxyPort = 8080;
- if (data.length > 1) {
- try {
- proxyPort = Integer.parseInt(data[1]);
- } catch (NumberFormatException e) {
- return;
- }
- }
- final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
- setGlobalProxy(p);
+ mProxyTracker.sendProxyBroadcast();
}
}
@@ -3752,7 +3766,7 @@
Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
}
- setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile));
+ setLockdownTracker(new LockdownVpnTracker(mContext, mNMS, this, vpn, profile));
} else {
setLockdownTracker(null);
}
@@ -3987,7 +4001,7 @@
@Override
public void setAirplaneMode(boolean enable) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackSettingsOrSetup();
final long ident = Binder.clearCallingIdentity();
try {
final ContentResolver cr = mContext.getContentResolver();
@@ -4007,7 +4021,7 @@
loge("Starting user already has a VPN");
return;
}
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
+ userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId);
mVpns.put(userId, userVpn);
if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
updateLockdownVpn();
@@ -4527,6 +4541,10 @@
// priority networks like Wi-Fi are active.
private final NetworkRequest mDefaultMobileDataRequest;
+ // Request used to optionally keep wifi data active even when higher
+ // priority networks like ethernet are active.
+ private final NetworkRequest mDefaultWifiRequest;
+
private NetworkAgentInfo getNetworkForRequest(int requestId) {
synchronized (mNetworkForRequestId) {
return mNetworkForRequestId.get(requestId);
@@ -4624,7 +4642,7 @@
mDnsManager.updatePrivateDnsStatus(netId, newLp);
// Start or stop clat accordingly to network state.
- networkAgent.updateClat(mNetd);
+ networkAgent.updateClat(mNMS);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
@@ -4663,9 +4681,9 @@
final String prefix = "iface:" + iface;
try {
if (add) {
- mNetd.getNetdService().wakeupAddInterface(iface, prefix, mark, mask);
+ mNetd.wakeupAddInterface(iface, prefix, mark, mask);
} else {
- mNetd.getNetdService().wakeupDelInterface(iface, prefix, mark, mask);
+ mNetd.wakeupDelInterface(iface, prefix, mark, mask);
}
} catch (Exception e) {
loge("Exception modifying wakeup packet monitoring: " + e);
@@ -4681,7 +4699,7 @@
for (String iface : interfaceDiff.added) {
try {
if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNetd.addInterfaceToNetwork(iface, netId);
+ mNMS.addInterfaceToNetwork(iface, netId);
wakeupModifyInterface(iface, caps, true);
} catch (Exception e) {
loge("Exception adding interface: " + e);
@@ -4691,7 +4709,7 @@
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, caps, false);
- mNetd.removeInterfaceFromNetwork(iface, netId);
+ mNMS.removeInterfaceFromNetwork(iface, netId);
} catch (Exception e) {
loge("Exception removing interface: " + e);
}
@@ -4715,7 +4733,7 @@
if (route.hasGateway()) continue;
if (VDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNetd.addRoute(netId, route);
+ mNMS.addRoute(netId, route);
} catch (Exception e) {
if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
loge("Exception in addRoute for non-gateway: " + e);
@@ -4726,7 +4744,7 @@
if (route.hasGateway() == false) continue;
if (VDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNetd.addRoute(netId, route);
+ mNMS.addRoute(netId, route);
} catch (Exception e) {
if ((route.getGateway() instanceof Inet4Address) || VDBG) {
loge("Exception in addRoute for gateway: " + e);
@@ -4737,7 +4755,7 @@
for (RouteInfo route : routeDiff.removed) {
if (VDBG) log("Removing Route [" + route + "] from network " + netId);
try {
- mNetd.removeRoute(netId, route);
+ mNMS.removeRoute(netId, route);
} catch (Exception e) {
loge("Exception in removeRoute: " + e);
}
@@ -4764,15 +4782,14 @@
}
}
- private String getNetworkPermission(NetworkCapabilities nc) {
- // TODO: make these permission strings AIDL constants instead.
+ private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
- return NetworkManagementService.PERMISSION_SYSTEM;
+ return INetd.PERMISSION_SYSTEM;
}
if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
- return NetworkManagementService.PERMISSION_NETWORK;
+ return INetd.PERMISSION_NETWORK;
}
- return null;
+ return INetd.PERMISSION_NONE;
}
/**
@@ -4845,11 +4862,11 @@
if (Objects.equals(nai.networkCapabilities, newNc)) return;
- final String oldPermission = getNetworkPermission(nai.networkCapabilities);
- final String newPermission = getNetworkPermission(newNc);
- if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
+ final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+ final int newPermission = getNetworkPermission(newNc);
+ if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
try {
- mNetd.setNetworkPermission(nai.network.netId, newPermission);
+ mNMS.setNetworkPermission(nai.network.netId, newPermission);
} catch (RemoteException e) {
loge("Exception in setNetworkPermission: " + e);
}
@@ -4909,12 +4926,12 @@
if (!newRanges.isEmpty()) {
final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
newRanges.toArray(addedRangesArray);
- mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray);
+ mNMS.addVpnUidRanges(nai.network.netId, addedRangesArray);
}
if (!prevRanges.isEmpty()) {
final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
prevRanges.toArray(removedRangesArray);
- mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+ mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);
}
} catch (Exception e) {
// Never crash!
@@ -5083,9 +5100,9 @@
private void makeDefault(NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
- setupDataActivityTracking(newNetwork);
+
try {
- mNetd.setDefaultNetId(newNetwork.network.netId);
+ mNMS.setDefaultNetId(newNetwork.network.netId);
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
@@ -5258,6 +5275,7 @@
}
}
if (isNewDefault) {
+ updateDataActivityTracking(newNetwork, oldDefaultNetwork);
// Notify system services that this network is up.
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
@@ -5480,12 +5498,12 @@
try {
// This should never fail. Specifying an already in use NetID will cause failure.
if (networkAgent.isVPN()) {
- mNetd.createVirtualNetwork(networkAgent.network.netId,
+ mNMS.createVirtualNetwork(networkAgent.network.netId,
!networkAgent.linkProperties.getDnsServers().isEmpty(),
(networkAgent.networkMisc == null ||
!networkAgent.networkMisc.allowBypass));
} else {
- mNetd.createPhysicalNetwork(networkAgent.network.netId,
+ mNMS.createPhysicalNetwork(networkAgent.network.netId,
getNetworkPermission(networkAgent.networkCapabilities));
}
} catch (Exception e) {
@@ -5511,15 +5529,7 @@
if (networkAgent.isVPN()) {
// Temporarily disable the default proxy (not global).
- synchronized (mProxyTracker.mProxyLock) {
- if (!mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = true;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(null);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(false);
// TODO: support proxy per network.
}
@@ -5541,15 +5551,7 @@
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- synchronized (mProxyTracker.mProxyLock) {
- if (mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = false;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(true);
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
disconnectAndDestroyNetwork(networkAgent);
@@ -5922,4 +5924,49 @@
pw.println(" Get airplane mode.");
}
}
+
+ /**
+ * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
+ * for testing.
+ */
+ private Vpn enforceActiveVpnOrNetworkStackPermission() {
+ if (checkNetworkStackPermission()) {
+ return null;
+ }
+ final int uid = Binder.getCallingUid();
+ final int user = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(user);
+ try {
+ if (vpn.getVpnInfo().ownerUid == uid) return vpn;
+ } catch (NullPointerException e) {
+ /* vpn is null, or VPN is not connected and getVpnInfo() is null. */
+ }
+ }
+ throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
+ + "permission");
+ }
+
+ /**
+ * @param connectionInfo the connection to resolve.
+ * @return {@code uid} if the connection is found and the app has permission to observe it
+ * (e.g., if it is associated with the calling VPN app's tunnel) or {@code INVALID_UID} if the
+ * connection is not found.
+ */
+ public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
+ final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
+ if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
+ throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
+ }
+
+ final int uid = InetDiagMessage.getConnectionOwnerUid(connectionInfo.protocol,
+ connectionInfo.local, connectionInfo.remote);
+
+ /* Filter out Uids not associated with the VPN. */
+ if (vpn != null && !vpn.appliesToUid(uid)) {
+ return INVALID_UID;
+ }
+
+ return uid;
+ }
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 380f6a7..8c25917 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -19,6 +19,8 @@
import static android.Manifest.permission.DUMP;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
import static android.system.OsConstants.EINVAL;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
@@ -63,6 +65,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
@@ -1426,6 +1430,17 @@
+ "or Encryption algorithms");
}
+ private int getFamily(String inetAddress) {
+ int family = AF_UNSPEC;
+ InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress);
+ if (checkAddress instanceof Inet4Address) {
+ family = AF_INET;
+ } else if (checkAddress instanceof Inet6Address) {
+ family = AF_INET6;
+ }
+ return family;
+ }
+
/**
* Checks an IpSecConfig parcel to ensure that the contents are sane and throws an
* IllegalArgumentException if they are not.
@@ -1479,6 +1494,26 @@
// Require a valid source address for all transforms.
checkInetAddress(config.getSourceAddress());
+ // Check to ensure source and destination have the same address family.
+ String sourceAddress = config.getSourceAddress();
+ String destinationAddress = config.getDestinationAddress();
+ int sourceFamily = getFamily(sourceAddress);
+ int destinationFamily = getFamily(destinationAddress);
+ if (sourceFamily != destinationFamily) {
+ throw new IllegalArgumentException(
+ "Source address ("
+ + sourceAddress
+ + ") and destination address ("
+ + destinationAddress
+ + ") have different address families.");
+ }
+
+ // Throw an error if UDP Encapsulation is not used in IPv4.
+ if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) {
+ throw new IllegalArgumentException(
+ "UDP Encapsulation is not supported for this address family");
+ }
+
switch (config.getMode()) {
case IpSecTransform.MODE_TRANSPORT:
break;
@@ -1490,23 +1525,19 @@
}
}
- private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
+ private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS;
private void enforceTunnelPermissions(String callingPackage) {
checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
- if (false) { // STOPSHIP if this line is present
- switch (getAppOpsManager().noteOp(
- TUNNEL_OP,
- Binder.getCallingUid(), callingPackage)) {
- case AppOpsManager.MODE_DEFAULT:
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
- break;
- case AppOpsManager.MODE_ALLOWED:
- return;
- default:
- throw new SecurityException("Request to ignore AppOps for non-legacy API");
- }
+ switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
+ case AppOpsManager.MODE_DEFAULT:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
+ break;
+ case AppOpsManager.MODE_ALLOWED:
+ return;
+ default:
+ throw new SecurityException("Request to ignore AppOps for non-legacy API");
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c79cf71..ab50059 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -57,6 +57,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
+import android.net.TetherStatsParcel;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
@@ -160,25 +161,14 @@
private static final int MAX_UID_RANGES_PER_COMMAND = 10;
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
/**
* Name representing {@link #setGlobalAlert(long)} limit when delivered to
* {@link INetworkManagementEventObserver#limitReached(String, String)}.
*/
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
- /**
- * String to pass to netd to indicate that a network is only accessible
- * to apps that have the CHANGE_NETWORK_STATE permission.
- */
- public static final String PERMISSION_NETWORK = "NETWORK";
-
- /**
- * String to pass to netd to indicate that a network is only
- * accessible to system apps and those with the CONNECTIVITY_INTERNAL
- * permission.
- */
- public static final String PERMISSION_SYSTEM = "SYSTEM";
-
static class NetdResponseCode {
/* Keep in sync with system/netd/server/ResponseCode.h */
public static final int InterfaceListResult = 110;
@@ -219,6 +209,9 @@
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
+ static final boolean MODIFY_OPERATION_ADD = true;
+ static final boolean MODIFY_OPERATION_REMOVE = false;
+
/**
* Binder context for this service
*/
@@ -1114,41 +1107,47 @@
@Override
public void addRoute(int netId, RouteInfo route) {
- modifyRoute("add", "" + netId, route);
+ modifyRoute(MODIFY_OPERATION_ADD, netId, route);
}
@Override
public void removeRoute(int netId, RouteInfo route) {
- modifyRoute("remove", "" + netId, route);
+ modifyRoute(MODIFY_OPERATION_REMOVE, netId, route);
}
- private void modifyRoute(String action, String netId, RouteInfo route) {
+ private void modifyRoute(boolean add, int netId, RouteInfo route) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final Command cmd = new Command("network", "route", action, netId);
-
- // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
- cmd.appendArg(route.getInterface());
- cmd.appendArg(route.getDestination().toString());
+ final String ifName = route.getInterface();
+ final String dst = route.getDestination().toString();
+ final String nextHop;
switch (route.getType()) {
case RouteInfo.RTN_UNICAST:
if (route.hasGateway()) {
- cmd.appendArg(route.getGateway().getHostAddress());
+ nextHop = route.getGateway().getHostAddress();
+ } else {
+ nextHop = INetd.NEXTHOP_NONE;
}
break;
case RouteInfo.RTN_UNREACHABLE:
- cmd.appendArg("unreachable");
+ nextHop = INetd.NEXTHOP_UNREACHABLE;
break;
case RouteInfo.RTN_THROW:
- cmd.appendArg("throw");
+ nextHop = INetd.NEXTHOP_THROW;
+ break;
+ default:
+ nextHop = INetd.NEXTHOP_NONE;
break;
}
-
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ if (add) {
+ mNetdService.networkAddRoute(netId, ifName, dst, nextHop);
+ } else {
+ mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1229,18 +1228,12 @@
@Override
public void startTethering(String[] dhcpRange) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // cmd is "tether start first_start first_stop second_start second_stop ..."
// an odd number of addrs will fail
- final Command cmd = new Command("tether", "start");
- for (String d : dhcpRange) {
- cmd.appendArg(d);
- }
-
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherStart(dhcpRange);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1248,9 +1241,9 @@
public void stopTethering() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "stop");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1258,25 +1251,21 @@
public boolean isTetheringStarted() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final NativeDaemonEvent event;
try {
- event = mConnector.execute("tether", "status");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final boolean isEnabled = mNetdService.tetherIsEnabled();
+ return isEnabled;
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
-
- // 210 Tethering services started
- event.checkCode(TetherStatusResult);
- return event.getMessage().endsWith("started");
}
@Override
public void tetherInterface(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "interface", "add", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherInterfaceAdd(iface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
List<RouteInfo> routes = new ArrayList<>();
// The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
@@ -1289,9 +1278,9 @@
public void untetherInterface(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "interface", "remove", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherInterfaceRemove(iface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
} finally {
removeInterfaceFromLocalNetwork(iface);
}
@@ -1301,11 +1290,10 @@
public String[] listTetheredInterfaces() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("tether", "interface", "list"),
- TetherInterfaceListResult);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final List<String> result = mNetdService.tetherInterfaceList();
+ return result.toArray(EMPTY_STRING_ARRAY);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1314,16 +1302,11 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
- final Command cmd = new Command("tether", "dns", "set", netId);
-
- for (String s : dns) {
- cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
- }
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherDnsSet(netId, dns);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1331,10 +1314,10 @@
public String[] getDnsForwarders() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final List<String> result = mNetdService.tetherDnsList();
+ return result.toArray(EMPTY_STRING_ARRAY);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1560,10 +1543,11 @@
try {
// TODO: support quota shared across interfaces
- mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
+ mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
+
mActiveQuotas.put(iface, quotaBytes);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
synchronized (mTetheringStatsProviders) {
@@ -1594,9 +1578,9 @@
try {
// TODO: support quota shared across interfaces
- mConnector.execute("bandwidth", "removeiquota", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.bandwidthRemoveInterfaceQuota(iface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
synchronized (mTetheringStatsProviders) {
@@ -1628,10 +1612,10 @@
try {
// TODO: support alert shared across interfaces
- mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
+ mNetdService.bandwidthSetInterfaceAlert(iface, alertBytes);
mActiveAlerts.put(iface, alertBytes);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -1648,10 +1632,10 @@
try {
// TODO: support alert shared across interfaces
- mConnector.execute("bandwidth", "removeinterfacealert", iface);
+ mNetdService.bandwidthRemoveInterfaceAlert(iface);
mActiveAlerts.remove(iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -1661,18 +1645,15 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("bandwidth", "setglobalalert", alertBytes);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.bandwidthSetGlobalAlert(alertBytes);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final String chain = blacklist ? "naughtyapps" : "niceapps";
- final String suffix = enable ? "add" : "remove";
-
synchronized (mQuotaLock) {
boolean oldEnable;
SparseBooleanArray quotaList;
@@ -1687,7 +1668,19 @@
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
try {
- mConnector.execute("bandwidth", suffix + chain, uid);
+ if (blacklist) {
+ if (enable) {
+ mNetdService.bandwidthAddNaughtyApp(uid);
+ } else {
+ mNetdService.bandwidthRemoveNaughtyApp(uid);
+ }
+ } else {
+ if (enable) {
+ mNetdService.bandwidthAddNiceApp(uid);
+ } else {
+ mNetdService.bandwidthRemoveNiceApp(uid);
+ }
+ }
synchronized (mRulesLock) {
if (enable) {
quotaList.put(uid, true);
@@ -1695,8 +1688,8 @@
quotaList.delete(uid);
}
}
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -1843,31 +1836,30 @@
return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
- final PersistableBundle bundle;
+ final TetherStatsParcel[] tetherStatsVec;
try {
- bundle = mNetdService.tetherGetStats();
+ tetherStatsVec = mNetdService.tetherGetStats();
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException("problem parsing tethering stats: ", e);
}
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(),
- bundle.size());
+ tetherStatsVec.length);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String iface : bundle.keySet()) {
- long[] statsArray = bundle.getLongArray(iface);
+ for (TetherStatsParcel tetherStats : tetherStatsVec) {
try {
- entry.iface = iface;
+ entry.iface = tetherStats.iface;
entry.uid = UID_TETHERING;
entry.set = SET_DEFAULT;
entry.tag = TAG_NONE;
- entry.rxBytes = statsArray[INetd.TETHER_STATS_RX_BYTES];
- entry.rxPackets = statsArray[INetd.TETHER_STATS_RX_PACKETS];
- entry.txBytes = statsArray[INetd.TETHER_STATS_TX_BYTES];
- entry.txPackets = statsArray[INetd.TETHER_STATS_TX_PACKETS];
+ entry.rxBytes = tetherStats.rxBytes;
+ entry.rxPackets = tetherStats.rxPackets;
+ entry.txBytes = tetherStats.txBytes;
+ entry.txPackets = tetherStats.txPackets;
stats.combineValues(entry);
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalStateException("invalid tethering stats for " + iface, e);
+ throw new IllegalStateException("invalid tethering stats " + e);
}
}
@@ -1915,44 +1907,21 @@
@Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "users";
- argv[1] = "add";
- argv[2] = netId;
- int argc = 3;
- // Avoid overly long commands by limiting number of UID ranges per command.
- for (int i = 0; i < ranges.length; i++) {
- argv[argc++] = ranges[i].toString();
- if (i == (ranges.length - 1) || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+
+ try {
+ mNetdService.networkAddUidRanges(netId, ranges);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
public void removeVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "users";
- argv[1] = "remove";
- argv[2] = netId;
- int argc = 3;
- // Avoid overly long commands by limiting number of UID ranges per command.
- for (int i = 0; i < ranges.length; i++) {
- argv[argc++] = ranges[i].toString();
- if (i == (ranges.length - 1) || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+ try {
+ mNetdService.networkRemoveUidRanges(netId, ranges);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2410,17 +2379,13 @@
}
@Override
- public void createPhysicalNetwork(int netId, String permission) {
+ public void createPhysicalNetwork(int netId, int permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- if (permission != null) {
- mConnector.execute("network", "create", netId, permission);
- } else {
- mConnector.execute("network", "create", netId);
- }
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkCreatePhysical(netId, permission);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2429,10 +2394,9 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
- secure ? "1" : "0");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkCreateVpn(netId, hasDNS, secure);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2453,20 +2417,24 @@
@Override
public void addInterfaceToNetwork(String iface, int netId) {
- modifyInterfaceInNetwork("add", "" + netId, iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
}
@Override
public void removeInterfaceFromNetwork(String iface, int netId) {
- modifyInterfaceInNetwork("remove", "" + netId, iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, netId, iface);
}
- private void modifyInterfaceInNetwork(String action, String netId, String iface) {
+ private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "interface", action, netId, iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ if (add) {
+ mNetdService.networkAddInterface(netId, iface);
+ } else {
+ mNetdService.networkRemoveInterface(netId, iface);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2474,20 +2442,20 @@
public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
-
- // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
final LinkAddress la = routeInfo.getDestinationLinkAddress();
- cmd.appendArg(routeInfo.getInterface());
- cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
- if (routeInfo.hasGateway()) {
- cmd.appendArg(routeInfo.getGateway().getHostAddress());
- }
+ final String ifName = routeInfo.getInterface();
+ final String dst = la.toString();
+ final String nextHop;
+ if (routeInfo.hasGateway()) {
+ nextHop = routeInfo.getGateway().getHostAddress();
+ } else {
+ nextHop = "";
+ }
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2496,9 +2464,9 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "default", "set", netId);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetDefault(netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2507,49 +2475,41 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "default", "clear");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkClearDefault();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
- public void setNetworkPermission(int netId, String permission) {
+ public void setNetworkPermission(int netId, int permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- if (permission != null) {
- mConnector.execute("network", "permission", "network", "set", permission, netId);
- } else {
- mConnector.execute("network", "permission", "network", "clear", netId);
- }
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetPermissionForNetwork(netId, permission);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
+ private int parsePermission(String permission) {
+ if (permission.equals("NETWORK")) {
+ return INetd.PERMISSION_NETWORK;
+ }
+ if (permission.equals("SYSTEM")) {
+ return INetd.PERMISSION_SYSTEM;
+ }
+ return INetd.PERMISSION_NONE;
+ }
@Override
public void setPermission(String permission, int[] uids) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "permission";
- argv[1] = "user";
- argv[2] = "set";
- argv[3] = permission;
- int argc = 4;
- // Avoid overly long commands by limiting number of UIDs per command.
- for (int i = 0; i < uids.length; ++i) {
- argv[argc++] = uids[i];
- if (i == uids.length - 1 || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 4;
- }
+ try {
+ mNetdService.networkSetPermissionForUser(parsePermission(permission), uids);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2557,22 +2517,10 @@
public void clearPermission(int[] uids) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "permission";
- argv[1] = "user";
- argv[2] = "clear";
- int argc = 3;
- // Avoid overly long commands by limiting number of UIDs per command.
- for (int i = 0; i < uids.length; ++i) {
- argv[argc++] = uids[i];
- if (i == uids.length - 1 || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+ try {
+ mNetdService.networkClearPermissionForUser(uids);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2581,9 +2529,9 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "protect", "allow", uid);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetProtectAllow(uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2592,26 +2540,26 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "protect", "deny", uid);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetProtectDeny(uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
- modifyInterfaceInNetwork("add", "local", iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, iface);
for (RouteInfo route : routes) {
if (!route.isDefaultRoute()) {
- modifyRoute("add", "local", route);
+ modifyRoute(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, route);
}
}
}
@Override
public void removeInterfaceFromLocalNetwork(String iface) {
- modifyInterfaceInNetwork("remove", "local", iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, iface);
}
@Override
@@ -2620,7 +2568,7 @@
for (RouteInfo route : routes) {
try {
- modifyRoute("remove", "local", route);
+ modifyRoute(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, route);
} catch (IllegalStateException e) {
failures++;
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 0955bed..ca74adc 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -49,7 +49,9 @@
import android.telephony.TelephonyManager;
import android.telephony.VoLteServiceState;
import android.util.LocalLog;
+import android.util.StatsLog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
@@ -82,7 +84,8 @@
* Eventually we may want to remove the notion of dummy value but for now this
* looks like the best approach.
*/
-class TelephonyRegistry extends ITelephonyRegistry.Stub {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
private static final boolean DBG = false; // STOPSHIP if true
private static final boolean DBG_LOC = false; // STOPSHIP if true
@@ -211,6 +214,9 @@
private PhoneCapability mPhoneCapability = null;
+ @TelephonyManager.RadioPowerState
+ private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
+
private final LocalLog mLocalLog = new LocalLog(100);
private PreciseDataConnectionState mPreciseDataConnectionState =
@@ -324,7 +330,8 @@
// calls go through a oneway interface and local calls going through a
// handler before they get to app code.
- TelephonyRegistry(Context context) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public TelephonyRegistry(Context context) {
CellLocation location = CellLocation.getEmpty();
mContext = context;
@@ -749,6 +756,13 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+ try {
+ r.callback.onRadioPowerStateChanged(mRadioPowerState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -1570,6 +1584,32 @@
}
}
+ public void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ if (!checkNotifyPermission("notifyRadioPowerStateChanged()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyRadioPowerStateChanged: state= " + state);
+ }
+
+ synchronized (mRecords) {
+ mRadioPowerState = state;
+
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)) {
+ try {
+ r.callback.onRadioPowerStateChanged(state);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -1607,6 +1647,7 @@
pw.println("mBackgroundCallState=" + mBackgroundCallState);
pw.println("mVoLteServiceState=" + mVoLteServiceState);
pw.println("mPhoneCapability=" + mPhoneCapability);
+ pw.println("mRadioPowerState=" + mRadioPowerState);
pw.decreaseIndent();
@@ -1644,6 +1685,7 @@
intent.putExtras(data);
// Pass the subscription along with the intent.
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -1680,8 +1722,12 @@
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
mBatteryStats.notePhoneOff();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__OFF);
} else {
mBatteryStats.notePhoneOn();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__ON);
}
} catch (RemoteException e) {
/* The remote entity disappeared, we can safely ignore the exception. */
@@ -1698,6 +1744,7 @@
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
}
// If the phoneId is invalid, the broadcast is for overall call state.
if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 59093c1..289143c 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -87,7 +87,7 @@
"media.metrics", // system/bin/mediametrics
"media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
"com.android.bluetooth", // Bluetooth service
- "statsd", // Stats daemon
+ "/system/bin/statsd", // Stats daemon
};
public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9d0a865..6c98711 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -717,8 +717,6 @@
// Whether we should use SCHED_FIFO for UI and RenderThreads.
private boolean mUseFifoUiScheduling = false;
- private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService";
-
BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
@@ -810,7 +808,7 @@
boolean asProto) {
if (asProto) return;
doDump(fd, pw, new String[]{"activities"}, asProto);
- doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto);
+ doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto);
}
@Override
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 784d62e..302e195 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -157,9 +157,11 @@
// LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
// LMK_PROCPRIO <pid> <uid> <prio>
// LMK_PROCREMOVE <pid>
+ // LMK_PROCPURGE
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
+ static final byte LMK_PROCPURGE = 3;
// These are the various interesting memory levels that we will give to
// the OOM killer. Note that the OOM killer only supports 6 slots, so we
@@ -808,31 +810,46 @@
return true;
}
+ // Never call directly, use writeLmkd() instead
+ private static boolean writeLmkdCommand(ByteBuffer buf) {
+ try {
+ sLmkdOutputStream.write(buf.array(), 0, buf.position());
+ } catch (IOException ex) {
+ Slog.w(TAG, "Error writing to lowmemorykiller socket");
+
+ try {
+ sLmkdSocket.close();
+ } catch (IOException ex2) {
+ }
+
+ sLmkdSocket = null;
+ return false;
+ }
+ return true;
+ }
+
private static void writeLmkd(ByteBuffer buf) {
for (int i = 0; i < 3; i++) {
if (sLmkdSocket == null) {
- if (openLmkdSocket() == false) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ie) {
- }
- continue;
+ if (openLmkdSocket() == false) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
}
- }
-
- try {
- sLmkdOutputStream.write(buf.array(), 0, buf.position());
- return;
- } catch (IOException ex) {
- Slog.w(TAG, "Error writing to lowmemorykiller socket");
-
- try {
- sLmkdSocket.close();
- } catch (IOException ex2) {
+ continue;
}
- sLmkdSocket = null;
+ // Purge any previously registered pids
+ ByteBuffer purge_buf = ByteBuffer.allocate(4);
+ purge_buf.putInt(LMK_PROCPURGE);
+ if (writeLmkdCommand(purge_buf) == false) {
+ // Write failed, skip the rest and retry
+ continue;
+ }
+ }
+ if (writeLmkdCommand(buf)) {
+ return;
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0b9832d..40f1437 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -236,7 +236,6 @@
private static final int MSG_PERSIST_RINGER_MODE = 3;
private static final int MSG_AUDIO_SERVER_DIED = 4;
private static final int MSG_PLAY_SOUND_EFFECT = 5;
- private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
private static final int MSG_LOAD_SOUND_EFFECTS = 7;
private static final int MSG_SET_FORCE_USE = 8;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
@@ -268,6 +267,7 @@
private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
+ private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
// end of messages handled under wakelock
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -627,6 +627,13 @@
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
+ // Pre-scale for Bluetooth Absolute Volume
+ private float[] mPrescaleAbsoluteVolume = new float[] {
+ 0.5f, // Pre-scale for index 1
+ 0.7f, // Pre-scale for index 2
+ 0.85f, // Pre-scale for index 3
+ };
+
private static Long mLastDeviceConnectMsgTime = new Long(0);
private NotificationManager mNm;
@@ -878,6 +885,23 @@
mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
mRecordMonitor.initMonitor();
+
+ final float[] preScale = new float[3];
+ preScale[0] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+ 1, 1);
+ preScale[1] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+ 1, 1);
+ preScale[2] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+ 1, 1);
+ for (int i = 0; i < preScale.length; i++) {
+ if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
+ mPrescaleAbsoluteVolume[i] = preScale[i];
+ }
+ }
+
}
public void systemReady() {
@@ -3811,6 +3835,10 @@
int delay = checkSendBecomingNoisyIntent(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
AudioSystem.DEVICE_NONE);
+ final String addr = btDevice == null ? "null" : btDevice.getAddress();
+ mDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "A2DP service connected: device addr=" + addr
+ + " state=" + state));
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_A2DP_SINK_CONNECTION_STATE,
state,
@@ -4521,13 +4549,21 @@
}
synchronized (mLastDeviceConnectMsgTime) {
long time = SystemClock.uptimeMillis() + delay;
- handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
- if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
- msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
- msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
- msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
+
+ if (msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
+ msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+ msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
+ msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
+ msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
+ msg == MSG_BTA2DP_DOCK_TIMEOUT) {
+ if (mLastDeviceConnectMsgTime >= time) {
+ // add a little delay to make sure messages are ordered as expected
+ time = mLastDeviceConnectMsgTime + 30;
+ }
mLastDeviceConnectMsgTime = time;
}
+
+ handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
}
}
@@ -4625,20 +4661,15 @@
}
}
- @Override
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
- {
- Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
-
- setBluetoothHearingAidDeviceConnectionState(
- device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
- }
-
public int setBluetoothHearingAidDeviceConnectionState(
BluetoothDevice device, int state, boolean suppressNoisyIntent,
int musicDevice)
{
int delay;
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setHearingAidDeviceConnectionState state=" + state
+ + " addr=" + device.getAddress()
+ + " supprNoisy=" + suppressNoisyIntent)).printLog(TAG));
synchronized (mConnectedDevices) {
if (!suppressNoisyIntent) {
int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
@@ -4666,7 +4697,14 @@
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
{
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
+ // only querying address as this is the only readily available field on the device
+ + " addr=" + device.getAddress()
+ + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
+ + " vol=" + a2dpVolume)).printLog(TAG));
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
+ mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored"));
return 0;
}
return setBluetoothA2dpDeviceConnectionStateInt(
@@ -4689,6 +4727,13 @@
} else {
delay = 0;
}
+
+ if (DEBUG_DEVICES) {
+ Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
+ + " state: " + state + " delay(ms): " + delay
+ + " suppressNoisyIntent: " + suppressNoisyIntent);
+ }
+
queueMsgUnderWakeLock(mAudioHandler,
(profile == BluetoothProfile.A2DP ?
MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
@@ -4879,18 +4924,12 @@
if (index == 0) {
// 0% for volume 0
index = 0;
- } else if (index == 1) {
- // 50% for volume 1
- index = (int)(mIndexMax * 0.5) /10;
- } else if (index == 2) {
- // 70% for volume 2
- index = (int)(mIndexMax * 0.70) /10;
- } else if (index == 3) {
- // 85% for volume 3
- index = (int)(mIndexMax * 0.85) /10;
+ } else if (index > 0 && index <= 3) {
+ // Pre-scale for volume steps 1 2 and 3
+ index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10;
} else {
// otherwise, full gain
- index = (mIndexMax + 5)/10;
+ index = (mIndexMax + 5) / 10;
}
return index;
}
@@ -5597,6 +5636,7 @@
synchronized (mConnectedDevices) {
makeA2dpDeviceUnavailableNow( (String) msg.obj );
}
+ mAudioEventWakeLock.release();
break;
case MSG_SET_FORCE_USE:
@@ -5611,7 +5651,7 @@
case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
{ WiredDeviceConnectionState connectState =
(WiredDeviceConnectionState)msg.obj;
- mWiredDevLogger.log(new WiredDevConnectEvent(connectState));
+ mDeviceLogger.log(new WiredDevConnectEvent(connectState));
onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
connectState.mAddress, connectState.mName, connectState.mCaller);
mAudioEventWakeLock.release();
@@ -5819,14 +5859,20 @@
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
private void onSendBecomingNoisyIntent() {
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
}
// must be called synchronized on mConnectedDevices
private void makeA2dpDeviceUnavailableNow(String address) {
+ if (address == null) {
+ return;
+ }
synchronized (mA2dpAvrcpLock) {
mAvrcpAbsVolSupported = false;
}
@@ -5835,7 +5881,10 @@
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
+ if (mDockAddress == address) {
+ mDockAddress = null;
+ }
}
// must be called synchronized on mConnectedDevices
@@ -5847,9 +5896,12 @@
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// send the delayed message to make the device unavailable later
- Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
- mAudioHandler.sendMessageDelayed(msg, delayMs);
-
+ queueMsgUnderWakeLock(mAudioHandler,
+ MSG_BTA2DP_DOCK_TIMEOUT,
+ 0,
+ 0,
+ address,
+ delayMs);
}
// must be called synchronized on mConnectedDevices
@@ -5896,6 +5948,10 @@
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_HEARING_AID, 0,
+ mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
// must be called synchronized on mConnectedDevices
@@ -5905,7 +5961,7 @@
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
// Remove Hearing Aid routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
}
// must be called synchronized on mConnectedDevices
@@ -5921,7 +5977,8 @@
private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
{
if (DEBUG_DEVICES) {
- Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
+ Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
+ + " is dock: "+btDevice.isBluetoothDock());
}
if (btDevice == null) {
return;
@@ -5949,7 +6006,6 @@
} else {
makeA2dpDeviceUnavailableNow(address);
}
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
@@ -5958,7 +6014,7 @@
} else {
// this could be a connection of another A2DP device before the timeout of
// a dock: cancel the dock timeout, and make the dock unavailable now
- if(hasScheduledA2dpDockTimeout()) {
+ if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
cancelA2dpDeviceTimeout();
makeA2dpDeviceUnavailableNow(mDockAddress);
}
@@ -5973,7 +6029,6 @@
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
@@ -6025,25 +6080,35 @@
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceUnavailable(address);
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceAvailable(address, btDevice.getName(),
"onSetHearingAidConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
- private void setCurrentAudioRouteName(String name){
+ private void setCurrentAudioRouteNameIfPossible(String name) {
synchronized (mCurAudioRoutes) {
if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
- mCurAudioRoutes.bluetoothName = name;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
+ if (name != null || !isCurrentDeviceConnected()) {
+ mCurAudioRoutes.bluetoothName = name;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
}
}
}
+ private boolean isCurrentDeviceConnected() {
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+ if (TextUtils.equals(deviceSpec.mDeviceName, mCurAudioRoutes.bluetoothName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_DEVICES) {
@@ -6056,10 +6121,14 @@
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
+ mDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "onBluetoothA2dpDeviceConfigChange addr=" + address));
int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
synchronized (mConnectedDevices) {
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
+ mDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "A2dp config change ignored"));
return;
}
final String key = makeDeviceListKey(device, address);
@@ -6177,17 +6246,6 @@
}
}
- if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
- mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
- mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
- mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
- synchronized (mLastDeviceConnectMsgTime) {
- long time = SystemClock.uptimeMillis();
- if (mLastDeviceConnectMsgTime > time) {
- delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
- }
- }
- }
return delay;
}
@@ -7166,19 +7224,20 @@
//==========================================================================================
// AudioService logging and dumpsys
//==========================================================================================
- final int LOG_NB_EVENTS_PHONE_STATE = 20;
- final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30;
- final int LOG_NB_EVENTS_FORCE_USE = 20;
- final int LOG_NB_EVENTS_VOLUME = 40;
- final int LOG_NB_EVENTS_DYN_POLICY = 10;
+ static final int LOG_NB_EVENTS_PHONE_STATE = 20;
+ static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
+ static final int LOG_NB_EVENTS_FORCE_USE = 20;
+ static final int LOG_NB_EVENTS_VOLUME = 40;
+ static final int LOG_NB_EVENTS_DYN_POLICY = 10;
final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
"phone state (logged after successfull call to AudioSystem.setPhoneState(int))");
- final private AudioEventLogger mWiredDevLogger = new AudioEventLogger(
- LOG_NB_EVENTS_WIRED_DEV_CONNECTION,
- "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)"
- );
+ // logs for wired + A2DP device connections:
+ // - wired: logged before onSetWiredDeviceConnectionState() is executed
+ // - A2DP: logged at reception of method call
+ final private AudioEventLogger mDeviceLogger = new AudioEventLogger(
+ LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP/hearing aid device connection");
final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
LOG_NB_EVENTS_FORCE_USE,
@@ -7267,7 +7326,7 @@
pw.println("\nEvent logs:");
mModeLogger.dump(pw);
pw.println("\n");
- mWiredDevLogger.dump(pw);
+ mDeviceLogger.dump(pw);
pw.println("\n");
mForceUseLogger.dump(pw);
pw.println("\n");
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ca9b256..30659c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1031,6 +1031,11 @@
result.isPortal() /* isCaptivePortal */,
startTime, endTime);
+ log("isCaptivePortal: isSuccessful()=" + result.isSuccessful() +
+ " isPortal()=" + result.isPortal() +
+ " RedirectUrl=" + result.redirectUrl +
+ " StartTime=" + startTime + " EndTime=" + endTime);
+
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index dc65e1e..15468ff 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,6 +16,12 @@
package com.android.server.connectivity;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.provider.Settings.Global.HTTP_PROXY;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -47,16 +53,14 @@
@NonNull
private final Context mContext;
- // TODO : make this private and import as much managing logic from ConnectivityService as
- // possible
@NonNull
- public final Object mProxyLock = new Object();
+ private final Object mProxyLock = new Object();
// The global proxy is the proxy that is set device-wide, overriding any network-specific
// proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
// this value is only for querying.
@Nullable
@GuardedBy("mProxyLock")
- public ProxyInfo mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
// The default proxy is the proxy that applies to no particular network if the global proxy
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
@@ -64,10 +68,10 @@
// when PacManager resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
- public volatile ProxyInfo mDefaultProxy = null;
- // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+ private volatile ProxyInfo mDefaultProxy = null;
+ // Whether the default proxy is enabled.
@GuardedBy("mProxyLock")
- public boolean mDefaultProxyDisabled = false;
+ private boolean mDefaultProxyEnabled = true;
// The object responsible for Proxy Auto Configuration (PAC).
@NonNull
@@ -85,7 +89,7 @@
@Nullable
private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+ && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
return null;
}
return proxy;
@@ -122,9 +126,9 @@
public ProxyInfo getDefaultProxy() {
// This information is already available as a world read/writable jvm property.
synchronized (mProxyLock) {
- final ProxyInfo ret = mGlobalProxy;
- if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
- return ret;
+ if (mGlobalProxy != null) return mGlobalProxy;
+ if (mDefaultProxyEnabled) return mDefaultProxy;
+ return null;
}
}
@@ -142,15 +146,68 @@
}
/**
+ * Read the global proxy settings and cache them in memory.
+ */
+ public void loadGlobalProxy() {
+ ContentResolver res = mContext.getContentResolver();
+ String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
+ if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
+ ProxyInfo proxyProperties;
+ if (!TextUtils.isEmpty(pacFileUrl)) {
+ proxyProperties = new ProxyInfo(pacFileUrl);
+ } else {
+ proxyProperties = new ProxyInfo(host, port, exclList);
+ }
+ if (!proxyProperties.isValid()) {
+ if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
+ return;
+ }
+
+ synchronized (mProxyLock) {
+ mGlobalProxy = proxyProperties;
+ }
+ }
+ loadDeprecatedGlobalHttpProxy();
+ // TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
+ }
+
+ /**
+ * Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
+ */
+ public void loadDeprecatedGlobalHttpProxy() {
+ final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
+ if (!TextUtils.isEmpty(proxy)) {
+ String data[] = proxy.split(":");
+ if (data.length == 0) {
+ return;
+ }
+
+ final String proxyHost = data[0];
+ int proxyPort = 8080;
+ if (data.length > 1) {
+ try {
+ proxyPort = Integer.parseInt(data[1]);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ }
+ final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
+ setGlobalProxy(p);
+ }
+ }
+
+ /**
* Sends the system broadcast informing apps about a new proxy configuration.
*
* Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
* to do in a "sendProxyBroadcast" method.
- * @param proxyInfo the proxy spec, or null for no proxy.
*/
- // TODO : make the argument NonNull final and the method private
- public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) {
- if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, "");
+ public void sendProxyBroadcast() {
+ final ProxyInfo defaultProxy = getDefaultProxy();
+ final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
@@ -203,16 +260,15 @@
final ContentResolver res = mContext.getContentResolver();
final long token = Binder.clearCallingIdentity();
try {
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
} finally {
Binder.restoreCallingIdentity(token);
}
- sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo);
+ sendProxyBroadcast();
}
}
@@ -224,10 +280,7 @@
*/
public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
synchronized (mProxyLock) {
- if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
- return;
- }
- if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+ if (Objects.equals(mDefaultProxy, proxyInfo)) return;
if (proxyInfo != null && !proxyInfo.isValid()) {
if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
@@ -242,14 +295,32 @@
&& (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
&& proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
mGlobalProxy = proxyInfo;
- sendProxyBroadcast(mGlobalProxy);
+ sendProxyBroadcast();
return;
}
mDefaultProxy = proxyInfo;
if (mGlobalProxy != null) return;
- if (!mDefaultProxyDisabled) {
- sendProxyBroadcast(proxyInfo);
+ if (mDefaultProxyEnabled) {
+ sendProxyBroadcast();
+ }
+ }
+ }
+
+ /**
+ * Enable or disable the default proxy.
+ *
+ * This sets the flag for enabling/disabling the default proxy and sends the broadcast
+ * if applicable.
+ * @param enabled whether the default proxy should be enabled.
+ */
+ public void setDefaultProxyEnabled(final boolean enabled) {
+ synchronized (mProxyLock) {
+ if (mDefaultProxyEnabled != enabled) {
+ mDefaultProxyEnabled = enabled;
+ if (mGlobalProxy == null && mDefaultProxy != null) {
+ sendProxyBroadcast();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d16c277..a8f7259 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.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.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 @@
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 @@
.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 @@
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 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 @@
}
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 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 @@
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 @@
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 @@
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 @@
}
}
- private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
+ private void handleInterfaceServingStateInactive(IpServer who) {
mNotifyList.remove(who);
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
void notify(int msgType) {
mErrorNotification = msgType;
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- sm.sendMessage(msgType);
+ for (IpServer ipServer : mNotifyList) {
+ ipServer.sendMessage(msgType);
}
}
@@ -1676,7 +1675,7 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
}
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 @@
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 @@
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 @@
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 @@
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/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2a80f0e..48082b6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -163,8 +163,8 @@
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
- private Context mContext;
- private NetworkInfo mNetworkInfo;
+ private final Context mContext;
+ private final NetworkInfo mNetworkInfo;
private String mPackage;
private int mOwnerUID;
private String mInterface;
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 2b81347..0000000
--- 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 ba67c94..1000148 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 @@
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 @@
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 @@
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 void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+ public void removeActiveDownstream(IpServer downstream) {
stopIPv6TetheringOn(downstream);
if (mActiveDownstreams.remove(findDownstream(downstream))) {
updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@
}
private void stopIPv6TetheringOnAllInterfaces() {
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- stopIPv6TetheringOn(sm);
+ for (IpServer ipServer : mNotifyList) {
+ stopIPv6TetheringOn(ipServer);
}
}
@@ -156,28 +156,28 @@
}
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 @@
// 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 @@
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 @@
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/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 2b1d919..1e6bb04 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -320,9 +320,8 @@
}
private static boolean getEnableLegacyDhcpServer(Context ctx) {
- // TODO: make the default false (0) and update javadoc in Settings.java
final ContentResolver cr = ctx.getContentResolver();
- final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
+ final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
return intVal != 0;
}
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 caa867c..8b40069 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.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 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 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/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 451acf4..7745e3c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1879,30 +1879,36 @@
// Read partner-provided list of excluded input devices
XmlPullParser parser = null;
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
- File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
- FileReader confreader = null;
- try {
- confreader = new FileReader(confFile);
- parser = Xml.newPullParser();
- parser.setInput(confreader);
- XmlUtils.beginDocument(parser, "devices");
+ final File[] baseDirs = {
+ Environment.getRootDirectory(),
+ Environment.getVendorDirectory()
+ };
+ for (File baseDir: baseDirs) {
+ File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
+ FileReader confreader = null;
+ try {
+ confreader = new FileReader(confFile);
+ parser = Xml.newPullParser();
+ parser.setInput(confreader);
+ XmlUtils.beginDocument(parser, "devices");
- while (true) {
- XmlUtils.nextElement(parser);
- if (!"device".equals(parser.getName())) {
- break;
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (!"device".equals(parser.getName())) {
+ break;
+ }
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ names.add(name);
+ }
}
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- names.add(name);
- }
+ } catch (FileNotFoundException e) {
+ // It's ok if the file does not exist.
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+ } finally {
+ try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
- } catch (FileNotFoundException e) {
- // It's ok if the file does not exist.
- } catch (Exception e) {
- Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
- } finally {
- try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
return names.toArray(new String[names.size()]);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 60e9eaa..3f03169 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -159,8 +159,10 @@
static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
+ // Perform polling and persist all (FLAG_PERSIST_ALL).
private static final int MSG_PERFORM_POLL = 1;
- private static final int MSG_REGISTER_GLOBAL_ALERT = 2;
+ // Perform polling, persist network, and register the global alert again.
+ private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -168,6 +170,14 @@
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private static final int FLAG_PERSIST_FORCE = 0x100;
+ /**
+ * When global alert quota is high, wait for this delay before processing each polling,
+ * and do not schedule further polls once there is already one queued.
+ * This avoids firing the global alert too often on devices with high transfer speeds and
+ * high quota.
+ */
+ private static final int PERFORM_POLL_DELAY_MS = 1000;
+
private static final String TAG_NETSTATS_ERROR = "netstats_error";
private final Context mContext;
@@ -920,7 +930,7 @@
}
// Create baseline stats
- mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL));
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL));
return normalizedRequest;
}
@@ -1055,13 +1065,12 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
- // kick off background poll to collect network stats; UID stats
- // are handled during normal polling interval.
- final int flags = FLAG_PERSIST_NETWORK;
- mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
-
- // re-arm global alert for next update
- mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
+ // kick off background poll to collect network stats unless there is already
+ // such a call pending; UID stats are handled during normal polling interval.
+ if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) {
+ mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT,
+ PERFORM_POLL_DELAY_MS);
+ }
}
}
};
@@ -1673,11 +1682,11 @@
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERFORM_POLL: {
- final int flags = msg.arg1;
- mService.performPoll(flags);
+ mService.performPoll(FLAG_PERSIST_ALL);
return true;
}
- case MSG_REGISTER_GLOBAL_ALERT: {
+ case MSG_PERFORM_POLL_REGISTER_ALERT: {
+ mService.performPoll(FLAG_PERSIST_NETWORK);
mService.registerGlobalAlert();
return true;
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 748cf08..dea7863 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -53,16 +53,13 @@
private final static String TAG = "OTADexopt";
private final static boolean DEBUG_DEXOPT = true;
- // The synthetic library dependencies denoting "no checks."
- private final static String[] NO_LIBRARIES =
- new String[] { PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK };
-
// The amount of "available" (free - low threshold) space necessary at the start of an OTA to
// not bulk-delete unused apps' odex files.
private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024; // 1GB.
private final Context mContext;
private final PackageManagerService mPackageManagerService;
+ private final MetricsLogger metricsLogger;
// TODO: Evaluate the need for WeakReferences here.
@@ -95,6 +92,7 @@
public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
this.mContext = context;
this.mPackageManagerService = packageManagerService;
+ metricsLogger = new MetricsLogger();
}
public static OtaDexoptService main(Context context,
@@ -286,8 +284,8 @@
throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The current version.
- builder.append("9 ");
+ // The current version. For v10, see b/115993344.
+ builder.append("10 ");
builder.append("dexopt");
@@ -336,11 +334,6 @@
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
String[] libraryDependencies = pkg.usesLibraryFiles;
- if (pkg.isSystem()) {
- // For system apps, we want to avoid classpaths checks.
- libraryDependencies = NO_LIBRARIES;
- }
-
optimizer.performDexOpt(pkg, libraryDependencies,
null /* ISAs */,
@@ -443,24 +436,22 @@
private void performMetricsLogging() {
long finalTime = System.nanoTime();
- MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
+ metricsLogger.histogram("ota_dexopt_available_space_before_mb",
inMegabytes(availableSpaceBefore));
- MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
+ metricsLogger.histogram("ota_dexopt_available_space_after_bulk_delete_mb",
inMegabytes(availableSpaceAfterBulkDelete));
- MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
+ metricsLogger.histogram("ota_dexopt_available_space_after_dexopt_mb",
inMegabytes(availableSpaceAfterDexopt));
- MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
- importantPackageCount);
- MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
+ metricsLogger.histogram("ota_dexopt_num_important_packages", importantPackageCount);
+ metricsLogger.histogram("ota_dexopt_num_other_packages", otherPackageCount);
- MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
- MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
- dexoptCommandCountExecuted);
+ metricsLogger.histogram("ota_dexopt_num_commands", dexoptCommandCountTotal);
+ metricsLogger.histogram("ota_dexopt_num_commands_executed", dexoptCommandCountExecuted);
final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
- MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
+ metricsLogger.histogram("ota_dexopt_time_s", elapsedTimeSeconds);
}
private static class OTADexoptPackageDexOptimizer extends
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 271d205..fae4db9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17529,7 +17529,8 @@
// Prepare the application profiles for the new code paths.
// This needs to be done before invoking dexopt so that any install-time profile
// can be used for optimizations.
- mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
+ mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()),
+ /* updateReferenceProfileContent= */ true);
// Check whether we need to dexopt the app.
//
@@ -22606,8 +22607,18 @@
//
// We also have to cover non system users because we do not call the usual install package
// methods for them.
+ //
+ // NOTE: in order to speed up first boot time we only create the current profile and do not
+ // update the content of the reference profile. A system image should already be configured
+ // with the right profile keys and the profiles for the speed-profile prebuilds should
+ // already be copied. That's done in #performDexOptUpgrade.
+ //
+ // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of
+ // manually copying them in #performDexOptUpgrade. When we do that we should have a more
+ // granular check here and only update the existing profiles.
if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
- mArtManagerService.prepareAppProfiles(pkg, userId);
+ mArtManagerService.prepareAppProfiles(pkg, userId,
+ /* updateReferenceProfileContent= */ false);
}
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 390c0cc..1fcb37f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -60,8 +60,6 @@
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.Streams;
import java.io.BufferedReader;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 0ba7822..1fb51b7 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.pm.dex;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Context;
@@ -57,8 +59,6 @@
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.util.NonNull;
-import libcore.util.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
@@ -389,7 +389,8 @@
* - create the current primary profile to save time at app startup time.
* - copy the profiles from the associated dex metadata file to the reference profile.
*/
- public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) {
+ public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+ boolean updateReferenceProfileContent) {
final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
if (user < 0) {
Slog.wtf(TAG, "Invalid user id: " + user);
@@ -404,8 +405,14 @@
for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
String codePath = codePathsProfileNames.keyAt(i);
String profileName = codePathsProfileNames.valueAt(i);
- File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
- String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+ String dexMetadataPath = null;
+ // Passing the dex metadata file to the prepare method will update the reference
+ // profile content. As such, we look for the dex metadata file only if we need to
+ // perform an update.
+ if (updateReferenceProfileContent) {
+ File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
+ dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+ }
synchronized (mInstaller) {
boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
profileName, codePath, dexMetadataPath);
@@ -423,9 +430,10 @@
/**
* Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
*/
- public void prepareAppProfiles(PackageParser.Package pkg, int[] user) {
+ public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+ boolean updateReferenceProfileContent) {
for (int i = 0; i < user.length; i++) {
- prepareAppProfiles(pkg, user[i]);
+ prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
}
}
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index e3e1590..602ce3b 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -93,7 +93,7 @@
@GuardedBy("mPackageUseInfoMap")
private final Map<String, PackageUseInfo> mPackageUseInfoMap;
- public PackageDexUsage() {
+ /* package */ PackageDexUsage() {
super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false);
mPackageUseInfoMap = new HashMap<>();
}
@@ -116,7 +116,7 @@
* @return true if the dex load constitutes new information, or false if this information
* has been seen before.
*/
- public boolean record(String owningPackageName, String dexPath, int ownerUserId,
+ /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId,
String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit,
String loadingPackageName, String classLoaderContext) {
if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
@@ -193,7 +193,7 @@
* Convenience method for sync reads which does not force the user to pass a useless
* (Void) null.
*/
- public void read() {
+ /* package */ void read() {
read((Void) null);
}
@@ -558,7 +558,7 @@
* Remove the usage data associated with package {@code packageName}.
* @return true if the package usage was found and removed successfully.
*/
- public boolean removePackage(String packageName) {
+ /* package */ boolean removePackage(String packageName) {
synchronized (mPackageUseInfoMap) {
return mPackageUseInfoMap.remove(packageName) != null;
}
@@ -653,11 +653,12 @@
return packages;
}
- public void clear() {
+ /* package */ void clear() {
synchronized (mPackageUseInfoMap) {
mPackageUseInfoMap.clear();
}
}
+
// Creates a deep copy of the class' mPackageUseInfoMap.
private Map<String, PackageUseInfo> clonePackageUseInfoMap() {
Map<String, PackageUseInfo> clone = new HashMap<>();
@@ -679,7 +680,7 @@
throw new IllegalArgumentException("Unknown bool encoding: " + bool);
}
- public String dump() {
+ /* package */ String dump() {
StringWriter sw = new StringWriter();
write(sw);
return sw.toString();
diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
new file mode 100644
index 0000000..c93af2a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm.dex"
+ }
+ ]
+ },
+ {
+ "name": "DexLoggerIntegrationTests"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 1cba1c7..a55b49f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -95,10 +95,22 @@
mIsShowing = showing;
mCallback.onShowingChanged();
- try {
- mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error informing keystore of screen lock", e);
+ int retry = 2;
+ while (retry > 0) {
+ try {
+ mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+ break;
+ } catch (RemoteException e) {
+ if (retry == 2) {
+ Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
+ + " -> refreshing service token and retrying");
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+ } else {
+ Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
+ }
+ --retry;
+ }
}
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 89efe12..902bafb 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -57,17 +57,6 @@
"frameworks/native/services",
"system/gatekeeper/include",
],
-
- product_variables: {
- arc: {
- cflags: [
- "-DUSE_ARC",
- ],
- srcs: [
- "com_android_server_ArcVideoService.cpp",
- ],
- }
- }
}
cc_defaults {
@@ -98,7 +87,6 @@
"libsensorservicehidl",
"libgui",
"libusbhost",
- "libsuspend",
"libtinyalsa",
"libEGL",
"libGLESv2",
@@ -109,6 +97,7 @@
"libutils",
"libhwui",
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"android.hardware.audio.common@2.0",
"android.hardware.broadcastradio@1.0",
@@ -130,6 +119,7 @@
"android.hardware.vr@1.0",
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
+ "android.system.suspend@1.0",
],
static_libs: [
@@ -142,7 +132,6 @@
shared_libs: [
"libarcbridge",
"libarcbridgeservice",
- "libarcvideobridge",
"libchrome",
"libmojo",
],
diff --git a/services/core/jni/com_android_server_ArcVideoService.cpp b/services/core/jni/com_android_server_ArcVideoService.cpp
deleted file mode 100644
index f93cd90..0000000
--- a/services/core/jni/com_android_server_ArcVideoService.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ArcVideoService"
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <media/arcvideobridge/IArcVideoBridge.h>
-#include <utils/Log.h>
-
-#include <base/bind.h>
-#include <base/bind_helpers.h>
-#include <mojo/edk/embedder/embedder.h>
-#include <mojo/public/cpp/bindings/binding.h>
-
-#include <arc/ArcBridgeSupport.h>
-#include <arc/ArcService.h>
-#include <arc/Future.h>
-#include <arc/IArcBridgeService.h>
-#include <arc/MojoProcessSupport.h>
-#include <components/arc/common/video.mojom.h>
-
-namespace {
-
-// [MinVersion] of OnVideoInstanceReady method in arc_bridge.mojom.
-constexpr int kMinimumArcBridgeHostVersion = 6;
-
-void onCaptureResult(arc::Future<arc::MojoBootstrapResult>* future, uint32_t version,
- mojo::ScopedHandle handle, const std::string& token) {
- mojo::edk::ScopedPlatformHandle scoped_platform_handle;
- MojoResult result =
- mojo::edk::PassWrappedPlatformHandle(handle.release().value(), &scoped_platform_handle);
- if (result != MOJO_RESULT_OK) {
- ALOGE("Received invalid file descriptor.");
- future->set(arc::MojoBootstrapResult());
- return;
- }
-
- base::ScopedFD fd(scoped_platform_handle.release().handle);
- future->set(arc::MojoBootstrapResult(std::move(fd), token, version));
-}
-
-} // namespace
-
-namespace arc {
-
-class VideoService : public mojom::VideoInstance,
- public ArcService,
- public android::BnArcVideoBridge {
-public:
- explicit VideoService(MojoProcessSupport* mojoProcessSupport)
- : mMojoProcessSupport(mojoProcessSupport), mBinding(this) {
- mMojoProcessSupport->arc_bridge_support().requestArcBridgeProxyAsync(
- this, kMinimumArcBridgeHostVersion);
- }
-
- ~VideoService() override { mMojoProcessSupport->disconnect(&mBinding, &mHostPtr); }
-
- // VideoInstance overrides:
- void InitDeprecated(mojom::VideoHostPtr hostPtr) override {
- Init(std::move(hostPtr), base::Bind(&base::DoNothing));
- }
-
- void Init(mojom::VideoHostPtr hostPtr, const InitCallback& callback) override {
- ALOGV("Init");
- mHostPtr = std::move(hostPtr);
- // A method must be called while we are still in a Mojo thread so the
- // proxy can perform lazy initialization and be able to be called from
- // non-Mojo threads later.
- // This also caches the version number so it can be obtained by calling
- // .version().
- mHostPtr.QueryVersion(base::Bind(
- [](const InitCallback& callback, uint32_t version) {
- ALOGI("VideoService ready (version=%d)", version);
- callback.Run();
- },
- callback));
- ALOGV("Init done");
- }
-
- // ArcService overrides:
- void ready(mojom::ArcBridgeHostPtr* bridgeHost) override {
- (*bridgeHost)->OnVideoInstanceReady(mBinding.CreateInterfacePtrAndBind());
- }
-
- void versionMismatch(uint32_t version) override {
- ALOGE("ArcBridgeHost version %d, does not support video (version %d)\n", version,
- kMinimumArcBridgeHostVersion);
- }
-
- // BnArcVideoBridge overrides:
- MojoBootstrapResult bootstrapVideoAcceleratorFactory() override {
- ALOGV("VideoService::bootstrapVideoAcceleratorFactory");
-
- Future<MojoBootstrapResult> future;
- mMojoProcessSupport->mojo_thread().getTaskRunner()->PostTask(
- FROM_HERE, base::Bind(&VideoService::bootstrapVideoAcceleratorFactoryOnMojoThread,
- base::Unretained(this), &future));
- return future.get();
- }
-
- int32_t hostVersion() override {
- ALOGV("VideoService::hostVersion");
- return mHostPtr.version();
- }
-
-private:
- void bootstrapVideoAcceleratorFactoryOnMojoThread(Future<MojoBootstrapResult>* future) {
- if (!mHostPtr) {
- ALOGE("mHostPtr is not ready yet");
- future->set(MojoBootstrapResult());
- return;
- }
- mHostPtr->OnBootstrapVideoAcceleratorFactory(
- base::Bind(&onCaptureResult, base::Unretained(future), mHostPtr.version()));
- }
-
- // Outlives VideoService.
- MojoProcessSupport* const mMojoProcessSupport;
- mojo::Binding<mojom::VideoInstance> mBinding;
- mojom::VideoHostPtr mHostPtr;
-};
-
-} // namespace arc
-
-namespace android {
-
-int register_android_server_ArcVideoService() {
- defaultServiceManager()->addService(
- String16("android.os.IArcVideoBridge"),
- new arc::VideoService(arc::MojoProcessSupport::getLeakyInstance()));
- return 0;
-}
-
-} // namespace android
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 02ad6c7..0ff60e4 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -30,6 +30,8 @@
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/system/suspend/1.0/ISystemSuspend.h>
+#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -39,7 +41,6 @@
#include <log/log.h>
#include <utils/misc.h>
#include <utils/Log.h>
-#include <suspend/autosuspend.h>
using android::hardware::Return;
using android::hardware::Void;
@@ -49,6 +50,8 @@
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
+using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::ISystemSuspendCallback;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -63,6 +66,7 @@
extern sp<IPowerV1_0> getPowerHalV1_0();
extern sp<IPowerV1_1> getPowerHalV1_1();
extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
+extern sp<ISystemSuspend> getSuspendHal();
// Java methods used in getLowPowerStats
static jmethodID jgetAndUpdatePlatformState = NULL;
@@ -70,16 +74,19 @@
static jmethodID jputVoter = NULL;
static jmethodID jputState = NULL;
-static void wakeup_callback(bool success)
-{
- ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
- int ret = sem_post(&wakeup_sem);
- if (ret < 0) {
- char buf[80];
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error posting wakeup sem: %s\n", buf);
+class WakeupCallback : public ISystemSuspendCallback {
+public:
+ Return<void> notifyWakeup(bool success) override {
+ ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
+ int ret = sem_post(&wakeup_sem);
+ if (ret < 0) {
+ char buf[80];
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error posting wakeup sem: %s\n", buf);
+ }
+ return Void();
}
-}
+};
static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
{
@@ -101,11 +108,14 @@
return -1;
}
ALOGV("Registering callback...");
- autosuspend_set_wakeup_callback(&wakeup_callback);
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ suspendHal->registerCallback(new WakeupCallback());
}
// Wait for wakeup.
ALOGV("Waiting for wakeup...");
+ // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup
+ // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events.
int ret = sem_wait(&wakeup_sem);
if (ret < 0) {
char buf[80];
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 3302dea..649f1a5 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -30,8 +30,8 @@
#include <utils/Log.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::Stats;
using android::bpf::hasBpfSupport;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index b2d35d4..0c9b5f4 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -19,6 +19,7 @@
//#define LOG_NDEBUG 0
#include <android/hardware/power/1.1/IPower.h>
+#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
@@ -35,7 +36,7 @@
#include <utils/Log.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
-#include <suspend/autosuspend.h>
+#include <hidl/ServiceManagement.h>
#include "com_android_server_power_PowerManagerService.h"
@@ -44,6 +45,9 @@
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
+using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::IWakeLock;
+using android::system::suspend::V1_0::WakeLockType;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -171,6 +175,46 @@
}
}
+static sp<ISystemSuspend> gSuspendHal = nullptr;
+static sp<IWakeLock> gSuspendBlocker = nullptr;
+static std::mutex gSuspendMutex;
+
+// Assume SystemSuspend HAL is always alive.
+// TODO: Force device to restart if SystemSuspend HAL dies.
+sp<ISystemSuspend> getSuspendHal() {
+ static std::once_flag suspendHalFlag;
+ std::call_once(suspendHalFlag, [](){
+ ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, "default");
+ gSuspendHal = ISystemSuspend::getService();
+ assert(gSuspendHal != nullptr);
+ });
+ return gSuspendHal;
+}
+
+void enableAutoSuspend() {
+ static bool enabled = false;
+
+ std::lock_guard<std::mutex> lock(gSuspendMutex);
+ if (!enabled) {
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ suspendHal->enableAutosuspend();
+ enabled = true;
+ }
+ if (gSuspendBlocker) {
+ gSuspendBlocker->release();
+ gSuspendBlocker.clear();
+ }
+}
+
+void disableAutoSuspend() {
+ std::lock_guard<std::mutex> lock(gSuspendMutex);
+ if (!gSuspendBlocker) {
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL,
+ "PowerManager.SuspendLockout");
+ }
+}
+
// ----------------------------------------------------------------------------
static void nativeInit(JNIEnv* env, jobject obj) {
@@ -207,13 +251,13 @@
static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
if (enable) {
android::base::Timer t;
- autosuspend_enable();
+ enableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD("Excessive delay in autosuspend_enable() while turning screen off");
}
} else {
android::base::Timer t;
- autosuspend_disable();
+ disableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD("Excessive delay in autosuspend_disable() while turning screen on");
}
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 93c4829..6c2a894 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -390,7 +390,11 @@
[&result, &sidebandStream](Result res, const native_handle_t* handle) {
result = res;
if (res == Result::OK) {
- sidebandStream = handle;
+ if (handle) {
+ sidebandStream = native_handle_clone(handle);
+ } else {
+ result = Result::UNKNOWN;
+ }
}
});
if (result != Result::OK) {
@@ -398,7 +402,7 @@
result);
return UNKNOWN_ERROR;
}
- connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, false);
+ connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, true);
}
connection.mSurface = surface;
if (connection.mSurface != nullptr) {
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 0ebef37..bb6e684 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -54,9 +54,6 @@
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
-#ifdef USE_ARC
-int register_android_server_ArcVideoService();
-#endif
};
using namespace android;
@@ -104,8 +101,5 @@
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsService(env);
-#ifdef USE_ARC
- register_android_server_ArcVideoService();
-#endif
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 0505204..47790ce 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -3,7 +3,6 @@
srcs: ["java/**/*.java"],
libs: [
- "conscrypt",
"services.core",
],
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 82a2895..439f313 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -459,6 +459,12 @@
}
}
+ // Diagnostic to ensure that the system is in a base healthy state. Done here as a common
+ // non-zygote process.
+ if (!VMRuntime.hasBootImageSpaces()) {
+ Slog.wtf(TAG, "Runtime is not running with a boot image!");
+ }
+
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 77a3e21..6ba7d94 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -1,5 +1,8 @@
package android.net.dhcp;
+import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
+import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
+
import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
@@ -381,6 +384,26 @@
}
/**
+ * Returns whether a parameter is included in the parameter request list option of this packet.
+ *
+ * <p>If there is no parameter request list option in the packet, false is returned.
+ *
+ * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
+ */
+ public boolean hasRequestedParam(byte paramId) {
+ if (mRequestedParams == null) {
+ return false;
+ }
+
+ for (byte reqParam : mRequestedParams) {
+ if (reqParam == paramId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Creates a new L3 packet (including IP header) containing the
* DHCP udp packet. This method relies upon the delegated method
* finishPacket() to insert the per-packet contents.
@@ -696,7 +719,11 @@
addTlv(buf, DHCP_ROUTER, mGateways);
addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
+ addTlv(buf, DHCP_HOST_NAME, mHostName);
addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
+ if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
+ addTlv(buf, DHCP_MTU, mMtu);
+ }
}
/**
@@ -1259,7 +1286,8 @@
boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
- Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
+ Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+ short mtu) {
DhcpPacket pkt = new DhcpOfferPacket(
transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
INADDR_ANY /* clientIp */, yourIp, mac);
@@ -1267,9 +1295,11 @@
pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout;
pkt.mDomainName = domainName;
+ pkt.mHostName = hostname;
pkt.mServerIdentifier = dhcpServerIdentifier;
pkt.mSubnetMask = netMask;
pkt.mBroadcastAddress = bcAddr;
+ pkt.mMtu = mtu;
if (metered) {
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
}
@@ -1283,7 +1313,8 @@
boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
- Inet4Address dhcpServerIdentifier, String domainName, boolean metered) {
+ Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+ short mtu) {
DhcpPacket pkt = new DhcpAckPacket(
transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
mac);
@@ -1291,9 +1322,11 @@
pkt.mDnsServers = dnsServers;
pkt.mLeaseTime = timeout;
pkt.mDomainName = domainName;
+ pkt.mHostName = hostname;
pkt.mSubnetMask = netMask;
pkt.mServerIdentifier = dhcpServerIdentifier;
pkt.mBroadcastAddress = bcAddr;
+ pkt.mMtu = mtu;
if (metered) {
pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
}
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
index 2b3d577..cee6fa9 100644
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ b/services/net/java/android/net/dhcp/DhcpServer.java
@@ -20,6 +20,7 @@
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
+import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
@@ -46,6 +47,7 @@
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
+import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
@@ -350,6 +352,19 @@
return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
}
+ /**
+ * Get the hostname from a lease if non-empty and requested in the incoming request.
+ * @param request The incoming request.
+ * @return The hostname, or null if not requested or empty.
+ */
+ @Nullable
+ private static String getHostnameIfRequested(@NonNull DhcpPacket request,
+ @NonNull DhcpLease lease) {
+ return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
+ ? lease.getHostname()
+ : null;
+ }
+
private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
@NonNull MacAddress clientMac) {
final boolean broadcastFlag = getBroadcastFlag(request, lease);
@@ -358,12 +373,14 @@
getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
final Inet4Address broadcastAddr = getBroadcastAddress(
mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
+ final String hostname = getHostnameIfRequested(request, lease);
final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
+ mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
+ mServingParams.metered, (short) mServingParams.linkMtu);
return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
}
@@ -374,13 +391,15 @@
// transmitOffer above
final boolean broadcastFlag = getBroadcastFlag(request, lease);
final int timeout = getLeaseTimeout(lease);
+ final String hostname = getHostnameIfRequested(request, lease);
final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout,
mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
new ArrayList<>(mServingParams.defaultRouters),
new ArrayList<>(mServingParams.dnsServers),
- mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered);
+ mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
+ mServingParams.metered, (short) mServingParams.linkMtu);
return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
}
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
deleted file mode 100644
index d9d4b96..0000000
--- a/services/net/java/android/net/dns/ResolvUtil.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.net.dns;
-
-import static android.system.OsConstants.AI_ADDRCONFIG;
-
-import android.net.Network;
-import android.net.NetworkUtils;
-import android.system.GaiException;
-import android.system.OsConstants;
-import android.system.StructAddrinfo;
-
-import libcore.io.Libcore;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-
-/**
- * DNS resolution utility class.
- *
- * @hide
- */
-public class ResolvUtil {
- // Non-portable DNS resolution flag.
- private static final long NETID_USE_LOCAL_NAMESERVERS = 0x80000000L;
-
- private ResolvUtil() {}
-
- public static InetAddress[] blockingResolveAllLocally(Network network, String name)
- throws UnknownHostException {
- // Use AI_ADDRCONFIG by default
- return blockingResolveAllLocally(network, name, AI_ADDRCONFIG);
- }
-
- public static InetAddress[] blockingResolveAllLocally(
- Network network, String name, int aiFlags) throws UnknownHostException {
- final StructAddrinfo hints = new StructAddrinfo();
- hints.ai_flags = aiFlags;
- // Other hints identical to the default Inet6AddressImpl implementation
- hints.ai_family = OsConstants.AF_UNSPEC;
- hints.ai_socktype = OsConstants.SOCK_STREAM;
-
- final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
-
- try {
- return Libcore.os.android_getaddrinfo(name, hints, (int) networkForResolv.netId);
- } catch (GaiException gai) {
- gai.rethrowAsUnknownHostException(name + ": TLS-bypass resolution failed");
- return null; // keep compiler quiet
- }
- }
-
- public static Network getNetworkWithUseLocalNameserversFlag(Network network) {
- final long netidForResolv = NETID_USE_LOCAL_NAMESERVERS | (long) network.netId;
- return new Network((int) netidForResolv);
- }
-
- public static Network makeNetworkWithPrivateDnsBypass(Network network) {
- return new Network(network) {
- @Override
- public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return blockingResolveAllLocally(network, host);
- }
- };
- }
-}
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
index fc07aa1..9512f1b 100644
--- a/services/net/java/android/net/ip/IpNeighborMonitor.java
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -40,7 +40,6 @@
import com.android.internal.util.BitUtils;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.net.InetAddress;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/net/java/android/net/ip/IpServer.java
similarity index 89%
rename from services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
rename to services/net/java/android/net/ip/IpServer.java
index 5accb45..823c0a1 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.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 @@
*
* @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 @@
// 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 @@
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 @@
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 @@
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 @@
mDeps = deps;
resetLinkProperties();
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- mServingMode = IControlsTethering.STATE_AVAILABLE;
+ mServingMode = STATE_AVAILABLE;
mInitialState = new InitialState();
mLocalHotspotState = new LocalHotspotState();
@@ -379,6 +430,8 @@
params.mtu = v6only.getMtu();
params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
+ if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
+
for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
@@ -498,6 +551,20 @@
}
}
+ private byte getHopLimit(String upstreamIface) {
+ try {
+ int upstreamHopLimit = Integer.parseUnsignedInt(
+ mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
+ // Add one hop to account for this forwarding device
+ upstreamHopLimit++;
+ // Cap the hop limit to 255.
+ return (byte) Integer.min(upstreamHopLimit, 255);
+ } catch (Exception e) {
+ mLog.e("Failed to find upstream interface hop limit", e);
+ }
+ return RaParams.DEFAULT_HOPLIMIT;
+ }
+
private void setRaParams(RaParams newParams) {
if (mRaDaemon != null) {
final RaParams deprecatedParams =
@@ -521,14 +588,12 @@
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 +604,7 @@
class InitialState extends State {
@Override
public void enter() {
- sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
+ sendInterfaceState(STATE_AVAILABLE);
}
@Override
@@ -549,10 +614,10 @@
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 +714,7 @@
// 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 +724,7 @@
}
if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
- sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
+ sendInterfaceState(STATE_LOCAL_ONLY);
}
@Override
@@ -685,7 +750,7 @@
// 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 +760,7 @@
}
if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
- sendInterfaceState(IControlsTethering.STATE_TETHERED);
+ sendInterfaceState(STATE_TETHERED);
}
@Override
@@ -817,7 +882,7 @@
@Override
public void enter() {
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
+ sendInterfaceState(STATE_UNAVAILABLE);
}
}
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 9d686ef..d197d01 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -28,7 +28,6 @@
import android.net.util.InterfaceParams;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.StructGroupReq;
import android.system.StructTimeval;
import android.util.Log;
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
new file mode 100644
index 0000000..af9e601
--- /dev/null
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -0,0 +1,187 @@
+/*
+ * 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.net.netlink;
+
+import static android.os.Process.INVALID_UID;
+import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.NETLINK_INET_DIAG;
+
+import android.os.Build;
+import android.os.Process;
+import android.system.ErrnoException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.DatagramSocket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A NetlinkMessage subclass for netlink inet_diag messages.
+ *
+ * see also: <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * @hide
+ */
+public class InetDiagMessage extends NetlinkMessage {
+ public static final String TAG = "InetDiagMessage";
+ private static final int TIMEOUT_MS = 500;
+
+ public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, int family, short flags) {
+ final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
+ nlMsgHdr.nlmsg_len = bytes.length;
+ nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+ nlMsgHdr.nlmsg_flags = flags;
+ nlMsgHdr.pack(byteBuffer);
+
+ final StructInetDiagReqV2 inetDiagReqV2 = new StructInetDiagReqV2(protocol, local, remote,
+ family);
+ inetDiagReqV2.pack(byteBuffer);
+ return bytes;
+ }
+
+ public StructInetDiagMsg mStructInetDiagMsg;
+
+ private InetDiagMessage(StructNlMsgHdr header) {
+ super(header);
+ mStructInetDiagMsg = new StructInetDiagMsg();
+ }
+
+ public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
+ final InetDiagMessage msg = new InetDiagMessage(header);
+ msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
+ return msg;
+ }
+
+ private static int lookupUidByFamily(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, int family, short flags,
+ FileDescriptor fd)
+ throws ErrnoException, InterruptedIOException {
+ byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
+ NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
+ ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
+
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
+ final StructNlMsgHdr hdr = nlMsg.getHeader();
+ if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
+ return INVALID_UID;
+ }
+ if (nlMsg instanceof InetDiagMessage) {
+ return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
+ }
+ return INVALID_UID;
+ }
+
+ private static final int FAMILY[] = {AF_INET6, AF_INET};
+
+ private static int lookupUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, FileDescriptor fd)
+ throws ErrnoException, InterruptedIOException {
+ int uid;
+
+ for (int family : FAMILY) {
+ /**
+ * For exact match lookup, swap local and remote for UDP lookups due to kernel
+ * bug which will not be fixed. See aosp/755889 and
+ * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
+ */
+ if (protocol == IPPROTO_UDP) {
+ uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
+ } else {
+ uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
+ }
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ }
+
+ /**
+ * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
+ * socket is not connected (and even if the socket is connected to a different destination).
+ * If we want this API to work for such packets, then on miss we need to do a second lookup
+ * with only the local address and port filled in.
+ * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
+ */
+ if (protocol == IPPROTO_UDP) {
+ try {
+ InetSocketAddress wildcard = new InetSocketAddress(
+ Inet6Address.getByName("::"), 0);
+ uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
+ uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ } catch (UnknownHostException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ return INVALID_UID;
+ }
+
+ /**
+ * Use an inet_diag socket to look up the UID associated with the input local and remote
+ * address/port and protocol of a connection.
+ */
+ public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote) {
+ try {
+ final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
+ NetlinkSocket.connectToKernel(fd);
+
+ return lookupUid(protocol, local, remote, fd);
+
+ } catch (ErrnoException | SocketException | IllegalArgumentException
+ | InterruptedIOException e) {
+ Log.e(TAG, e.toString());
+ }
+ return INVALID_UID;
+ }
+
+ @Override
+ public String toString() {
+ return "InetDiagMessage{ "
+ + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
+ + "inet_diag_msg{"
+ + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
index e331701..fc1551c 100644
--- a/services/net/java/android/net/netlink/NetlinkConstants.java
+++ b/services/net/java/android/net/netlink/NetlinkConstants.java
@@ -54,6 +54,12 @@
return String.valueOf(family);
}
+ public static String stringForProtocol(int protocol) {
+ if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
+ if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
+ return String.valueOf(protocol);
+ }
+
public static String hexify(byte[] bytes) {
if (bytes == null) { return "(null)"; }
return HexDump.toHexString(bytes);
@@ -90,6 +96,9 @@
public static final short RTM_GETRULE = 34;
public static final short RTM_NEWNDUSEROPT = 68;
+ /* see <linux_src>/include/uapi/linux/sock_diag.h */
+ public static final short SOCK_DIAG_BY_FAMILY = 20;
+
public static String stringForNlMsgType(short nlm_type) {
switch (nlm_type) {
case NLMSG_NOOP: return "NLMSG_NOOP";
diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
index 3bf75ca..a325db8 100644
--- a/services/net/java/android/net/netlink/NetlinkMessage.java
+++ b/services/net/java/android/net/netlink/NetlinkMessage.java
@@ -69,6 +69,8 @@
case NetlinkConstants.RTM_DELNEIGH:
case NetlinkConstants.RTM_GETNEIGH:
return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
+ case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
+ return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
default:
if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
// Netlink control message. Just parse the header for now,
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index cfcba3a..40098c1 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -32,7 +32,6 @@
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java
new file mode 100644
index 0000000..da824ad
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagMsg.java
@@ -0,0 +1,67 @@
+/*
+ * 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.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import android.util.Log;
+
+/**
+ * struct inet_diag_msg
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_msg {
+ * __u8 idiag_family;
+ * __u8 idiag_state;
+ * __u8 idiag_timer;
+ * __u8 idiag_retrans;
+ * struct inet_diag_sockid id;
+ * __u32 idiag_expires;
+ * __u32 idiag_rqueue;
+ * __u32 idiag_wqueue;
+ * __u32 idiag_uid;
+ * __u32 idiag_inode;
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagMsg {
+ public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
+ private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
+ StructInetDiagSockId.STRUCT_SIZE + 12;
+ public int idiag_uid;
+
+ public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
+ StructInetDiagMsg struct = new StructInetDiagMsg();
+ struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
+ return struct;
+ }
+
+ @Override
+ public String toString() {
+ return "StructInetDiagMsg{ "
+ + "idiag_uid{" + idiag_uid + "}, "
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
new file mode 100644
index 0000000..49a9325
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
@@ -0,0 +1,80 @@
+/*
+ * 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.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_req_v2 {
+ * __u8 sdiag_family;
+ * __u8 sdiag_protocol;
+ * __u8 idiag_ext;
+ * __u8 pad;
+ * __u32 idiag_states;
+ * struct inet_diag_sockid id;
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagReqV2 {
+ public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
+
+ private final byte sdiag_family;
+ private final byte sdiag_protocol;
+ private final StructInetDiagSockId id;
+ private final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
+
+
+ public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
+ int family) {
+ sdiag_family = (byte) family;
+ sdiag_protocol = (byte) protocol;
+ id = new StructInetDiagSockId(local, remote);
+ }
+
+ public void pack(ByteBuffer byteBuffer) {
+ // The ByteOrder must have already been set by the caller.
+ byteBuffer.put((byte) sdiag_family);
+ byteBuffer.put((byte) sdiag_protocol);
+ byteBuffer.put((byte) 0);
+ byteBuffer.put((byte) 0);
+ byteBuffer.putInt(INET_DIAG_REQ_V2_ALL_STATES);
+ id.pack(byteBuffer);
+ }
+
+ @Override
+ public String toString() {
+ final String familyStr = NetlinkConstants.stringForAddressFamily(sdiag_family);
+ final String protocolStr = NetlinkConstants.stringForAddressFamily(sdiag_protocol);
+
+ return "StructInetDiagReqV2{ "
+ + "sdiag_family{" + familyStr + "}, "
+ + "sdiag_protocol{" + protocolStr + "}, "
+ + "idiag_ext{" + 0 + ")}, "
+ + "pad{" + 0 + "}, "
+ + "idiag_states{" + Integer.toHexString(INET_DIAG_REQ_V2_ALL_STATES) + "}, "
+ + id.toString()
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java
new file mode 100644
index 0000000..2e9fa25
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagSockId.java
@@ -0,0 +1,86 @@
+/*
+ * 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.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_sockid {
+ * __be16 idiag_sport;
+ * __be16 idiag_dport;
+ * __be32 idiag_src[4];
+ * __be32 idiag_dst[4];
+ * __u32 idiag_if;
+ * __u32 idiag_cookie[2];
+ * #define INET_DIAG_NOCOOKIE (~0U)
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagSockId {
+ public static final int STRUCT_SIZE = 48;
+
+ private final InetSocketAddress mLocSocketAddress;
+ private final InetSocketAddress mRemSocketAddress;
+ private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+ private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
+ mLocSocketAddress = loc;
+ mRemSocketAddress = rem;
+ }
+
+ public void pack(ByteBuffer byteBuffer) {
+ byteBuffer.order(BIG_ENDIAN);
+ byteBuffer.putShort((short) mLocSocketAddress.getPort());
+ byteBuffer.putShort((short) mRemSocketAddress.getPort());
+ byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
+ if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
+ byteBuffer.put(IPV4_PADDING);
+ }
+ byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
+ if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
+ byteBuffer.put(IPV4_PADDING);
+ }
+ byteBuffer.order(ByteOrder.nativeOrder());
+ byteBuffer.putInt(0);
+ byteBuffer.put(INET_DIAG_NOCOOKIE);
+ }
+
+ @Override
+ public String toString() {
+ return "StructInetDiagSockId{ "
+ + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
+ + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
+ + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
+ + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
+ + "idiag_if{" + 0 + "} "
+ + "idiag_cookie{INET_DIAG_NOCOOKIE}"
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index f7bf393..5a73a4e 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -17,6 +17,7 @@
package android.net.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -92,10 +93,17 @@
}
/**
- * Log an error due to an exception, with the exception stacktrace.
+ * Log an error due to an exception, with the exception stacktrace if provided.
+ *
+ * <p>The error and exception message appear in the shared log, but the stacktrace is only
+ * logged in general log output (logcat).
*/
- public void e(@NonNull String msg, @NonNull Throwable e) {
- Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e);
+ public void e(@NonNull String msg, @Nullable Throwable exception) {
+ if (exception == null) {
+ e(msg);
+ return;
+ }
+ Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
}
public void i(String msg) {
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 3d7fdbdd..de54c4b 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -80,7 +80,7 @@
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-3.6.1-prebuilt
+ platform-robolectric-3.6.2-prebuilt
LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests
@@ -105,4 +105,4 @@
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.6.2/run_robotests.mk
diff --git a/services/tests/runtests.py b/services/tests/runtests.py
index 7980dc2..f19cc5d 100755
--- a/services/tests/runtests.py
+++ b/services/tests/runtests.py
@@ -22,8 +22,7 @@
'android.support.test.runner.AndroidJUnitRunner')
PACKAGE_WHITELIST = (
- 'android.net',
- 'com.android.server.connectivity',
+ "com.android.server",
)
COLOR_RED = '\033[0;31m'
@@ -37,14 +36,27 @@
COLOR_NONE)
return subprocess.check_call(shell_command, shell=True)
-
+# usage:
+# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py : run tests in com.android.server
+# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py -e package [package name, e.g. com.android.server]
+# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py -e class [class name, e.g. com.android.server.MountServiceTests]
+#
+# The available INSTRUMENTED_PACKAGE_RUNNER may differ in different environments.
+# In this case, use "adb shell pm list instrumentation" to query available runners
+# and use the environment variable INSTRUMENTED_PACKAGE_RUNNER to overwrite
+# the default one, e.g.,
+# INSTRUMENTED_PACKAGE_RUNNER=com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner \
+# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py
+#
def main():
build_top = os.environ.get('ANDROID_BUILD_TOP', None)
out_dir = os.environ.get('OUT', None)
+ runner = os.environ.get('INSTRUMENTED_PACKAGE_RUNNER', None)
if build_top is None or out_dir is None:
print 'You need to source and lunch before you can use this script'
return 1
-
+ if runner is None:
+ runner = INSTRUMENTED_PACKAGE_RUNNER
print 'Building tests...'
run('make -j32 -C %s -f build/core/main.mk '
'MODULES-IN-frameworks-base-services-tests-servicestests' % build_top,
@@ -57,19 +69,19 @@
apk_path = (
'%s/data/app/FrameworksServicesTests/FrameworksServicesTests.apk' %
out_dir)
- run('adb install -r -g "%s"' % apk_path)
+ run('adb install -t -r -g "%s"' % apk_path)
print 'Running tests...'
if len(sys.argv) != 1:
run('adb shell am instrument -w %s "%s"' %
- (' '.join(sys.argv[1:]), INSTRUMENTED_PACKAGE_RUNNER))
+ (' '.join(sys.argv[1:]), runner))
return 0
# It would be nice if the activity manager accepted a list of packages, but
# in lieu of that...
for package in PACKAGE_WHITELIST:
run('adb shell am instrument -w -e package %s %s' %
- (package, INSTRUMENTED_PACKAGE_RUNNER))
+ (package, runner))
return 0
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index a85f21c..00ebae6 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -9,7 +9,9 @@
LOCAL_MODULE_TAGS := tests
# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, utils) \
LOCAL_STATIC_JAVA_LIBRARIES := \
frameworks-base-testutils \
@@ -55,6 +57,7 @@
libbacktrace \
libbase \
libbinder \
+ libbinderthreadstate \
libc++ \
libcutils \
liblog \
diff --git a/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java b/services/tests/servicestests/utils/com/android/server/testutils/OffsettableClock.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java
rename to services/tests/servicestests/utils/com/android/server/testutils/OffsettableClock.java
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
rename to services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestUtils.java b/services/tests/servicestests/utils/com/android/server/testutils/TestUtils.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/testutils/TestUtils.java
rename to services/tests/servicestests/utils/com/android/server/testutils/TestUtils.java
diff --git a/services/tests/uiservicestests/Android.mk b/services/tests/uiservicestests/Android.mk
index b98bc89..3fa776c 100644
--- a/services/tests/uiservicestests/Android.mk
+++ b/services/tests/uiservicestests/Android.mk
@@ -45,6 +45,7 @@
libbacktrace \
libbase \
libbinder \
+ libbinderthreadstate \
libc++ \
libcutils \
liblog \
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 942a07a..96ac935 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -121,7 +121,7 @@
cal.set(Calendar.MINUTE, 15);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 1;
mScheduleInfo.endHour = 3;
mScheduleInfo.startMinute = 15;
@@ -149,7 +149,7 @@
cal.set(Calendar.MINUTE, 15);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.endHour = 3;
mScheduleInfo.startMinute = 15;
@@ -250,7 +250,7 @@
calAlarm.add(Calendar.DATE, 1); // add a day
// ScheduleInfo: day 1, day 2: 9pm-7am
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 21;
mScheduleInfo.endHour = 7;
mScheduleInfo.startMinute = 0;
@@ -418,7 +418,7 @@
now.set(Calendar.MILLISECOND, 0);
now.add(Calendar.DATE, 1); // add a day
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.startMinute = 15;
mScheduleInfo.endHour = 3;
@@ -446,7 +446,7 @@
now.set(Calendar.MILLISECOND, 0);
now.add(Calendar.DATE, 1); // add a day
- mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+ mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
mScheduleInfo.startMinute = 15;
mScheduleInfo.endHour = 3;
@@ -464,4 +464,10 @@
private int getTodayDay() {
return new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
}
+
+ private int getTodayDay(int offset) {
+ Calendar cal = new GregorianCalendar();
+ cal.add(Calendar.DATE, offset);
+ return cal.get(Calendar.DAY_OF_WEEK);
+ }
}
diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk
new file mode 100644
index 0000000..0f8b18a
--- /dev/null
+++ b/services/tests/wmtests/Android.mk
@@ -0,0 +1,41 @@
+#########################################################################
+# Build WmTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, ../servicestests/utils)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx-test \
+ mockito-target-minus-junit4 \
+ platform-test-annotations \
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.mock \
+ android.test.base \
+ android.test.runner \
+
+LOCAL_PACKAGE_NAME := WmTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
new file mode 100644
index 0000000..1fb9473
--- /dev/null
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.wmtests">
+
+ <!-- Uses API introduced in P (28) -->
+ <uses-sdk
+ android:minSdkVersion="1"
+ android:targetSdkVersion="28" />
+
+ <application android:testOnly="true" />
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Window Manager Tests"
+ android:targetPackage="com.android.frameworks.wmtests" />
+</manifest>
diff --git a/services/tests/wmtests/AndroidTest.xml b/services/tests/wmtests/AndroidTest.xml
new file mode 100644
index 0000000..2717ef90
--- /dev/null
+++ b/services/tests/wmtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs Window Manager Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="WmTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="WmTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.wmtests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java b/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java
new file mode 100644
index 0000000..023e4ab
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Dummy test for com.android.server.am.
+ * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests.
+ */
+public class DummyAmTests {
+
+ @Presubmit
+ @Test
+ public void preSubmitTest() {}
+
+ @FlakyTest
+ @Presubmit
+ @Test
+ public void flakyPreSubmitTest() {}
+
+ @Test
+ public void postSubmitTest() {}
+
+ @FlakyTest
+ @Test
+ public void flakyPostSubmitTest() {}
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java b/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java
new file mode 100644
index 0000000..aecb278
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Dummy test for com.android.server.wm
+ * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests.
+ */
+public class DummyWmTests {
+
+ @Presubmit
+ @Test
+ public void preSubmitTest() {}
+
+ @FlakyTest
+ @Presubmit
+ @Test
+ public void flakyPreSubmitTest() {}
+
+ @Test
+ public void postSubmitTest() {}
+
+ @FlakyTest
+ @Test
+ public void flakyPostSubmitTest() {}
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 36f8063..4da7285 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -539,7 +539,8 @@
// We do not show the USB notification if the primary volume supports mass storage.
// The legacy mass storage UI will be used instead.
final StorageManager storageManager = StorageManager.from(mContext);
- final StorageVolume primary = storageManager.getPrimaryVolume();
+ final StorageVolume primary =
+ storageManager != null ? storageManager.getPrimaryVolume() : null;
boolean massStorageSupported = primary != null && primary.allowMassStorage();
mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
new file mode 100644
index 0000000..b3b0900
--- /dev/null
+++ b/startop/iorap/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library_static {
+ name: "libiorap-java",
+
+ aidl: {
+ include_dirs: [
+ "system/iorap/binder",
+ ],
+ },
+
+ srcs: [
+ ":iorap-aidl",
+ "**/*.java",
+ ],
+}
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
new file mode 100644
index 0000000..8c9d4df
--- /dev/null
+++ b/startop/iorap/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "libiorap-java-tests"
+ }
+ ],
+ "imports": [
+ {
+ "path": "system/iorap"
+ }
+ ]
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java
new file mode 100644
index 0000000..1d38f4c
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java
@@ -0,0 +1,139 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Provide a hint to iorapd that an activity has transitioned state.<br /><br />
+ *
+ * Knowledge of when an activity starts/stops can be used by iorapd to increase system
+ * performance (e.g. by launching perfetto tracing to record an io profile, or by
+ * playing back an ioprofile via readahead) over the long run.<br /><br />
+ *
+ * /@see com.google.android.startop.iorap.IIorap#onActivityHintEvent<br /><br />
+ *
+ * Once an activity hint is in {@link #TYPE_STARTED} it must transition to another type.
+ * All other states could be terminal, see below: <br /><br />
+ *
+ * <pre>
+ *
+ * ┌──────────────────────────────────────┐
+ * │ ▼
+ * ┌─────────┐ ╔════════════════╗ ╔═══════════╗
+ * ──▶ │ STARTED │ ──▶ ║ COMPLETED ║ ──▶ ║ CANCELLED ║
+ * └─────────┘ ╚════════════════╝ ╚═══════════╝
+ * │
+ * │
+ * ▼
+ * ╔════════════════╗
+ * ║ POST_COMPLETED ║
+ * ╚════════════════╝
+ *
+ * </pre> <!-- system/iorap/docs/binder/ActivityHint.dot -->
+ *
+ * @hide
+ */
+public class ActivityHintEvent implements Parcelable {
+
+ public static final int TYPE_STARTED = 0;
+ public static final int TYPE_CANCELLED = 1;
+ public static final int TYPE_COMPLETED = 2;
+ public static final int TYPE_POST_COMPLETED = 3;
+ private static final int TYPE_MAX = TYPE_POST_COMPLETED;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_STARTED,
+ TYPE_CANCELLED,
+ TYPE_COMPLETED,
+ TYPE_POST_COMPLETED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ @Type public final int type;
+ public final ActivityInfo activityInfo;
+
+ public ActivityHintEvent(@Type int type, ActivityInfo activityInfo) {
+ this.type = type;
+ this.activityInfo = activityInfo;
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkTypeInRange(type, TYPE_MAX);
+ Objects.requireNonNull(activityInfo, "activityInfo");
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{type: %d, activityInfo: %s}", type, activityInfo);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof ActivityHintEvent) {
+ return equals((ActivityHintEvent) other);
+ }
+ return false;
+ }
+
+ private boolean equals(ActivityHintEvent other) {
+ return type == other.type &&
+ Objects.equals(activityInfo, other.activityInfo);
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(type);
+ activityInfo.writeToParcel(out, flags);
+ }
+
+ private ActivityHintEvent(Parcel in) {
+ this.type = in.readInt();
+ this.activityInfo = ActivityInfo.CREATOR.createFromParcel(in);
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<ActivityHintEvent> CREATOR
+ = new Parcelable.Creator<ActivityHintEvent>() {
+ public ActivityHintEvent createFromParcel(Parcel in) {
+ return new ActivityHintEvent(in);
+ }
+
+ public ActivityHintEvent[] newArray(int size) {
+ return new ActivityHintEvent[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java
new file mode 100644
index 0000000..f47a42c
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.startop.iorap;
+
+import java.util.Objects;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Provide minimal information for launched activities to iorap.<br /><br />
+ *
+ * This uniquely identifies a system-wide activity by providing the {@link #packageName} and
+ * {@link #activityName}.
+ *
+ * @see ActivityHintEvent
+ * @see AppIntentEvent
+ *
+ * @hide
+ */
+public class ActivityInfo implements Parcelable {
+
+ /** The name of the package, for example {@code com.android.calculator}. */
+ public final String packageName;
+ /** The name of the activity, for example {@code .activities.activity.MainActivity} */
+ public final String activityName;
+
+ public ActivityInfo(String packageName, String activityName) {
+ this.packageName = packageName;
+ this.activityName = activityName;
+
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ Objects.requireNonNull(packageName, "packageName");
+ Objects.requireNonNull(activityName, "activityName");
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{packageName: %s, activityName: %s}", packageName, activityName);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof ActivityInfo) {
+ return equals((ActivityInfo) other);
+ }
+ return false;
+ }
+
+ private boolean equals(ActivityInfo other) {
+ return Objects.equals(packageName, other.packageName) &&
+ Objects.equals(activityName, other.activityName);
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(packageName);
+ out.writeString(activityName);
+ }
+
+ private ActivityInfo(Parcel in) {
+ packageName = in.readString();
+ activityName = in.readString();
+
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<ActivityInfo> CREATOR
+ = new Parcelable.Creator<ActivityInfo>() {
+ public ActivityInfo createFromParcel(Parcel in) {
+ return new ActivityInfo(in);
+ }
+
+ public ActivityInfo[] newArray(int size) {
+ return new ActivityInfo[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java
new file mode 100644
index 0000000..1cd37b5
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java
@@ -0,0 +1,138 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Notifications for iorapd specifying when a system-wide intent defaults change.<br /><br />
+ *
+ * Intent defaults provide a mechanism for an app to register itself as an automatic handler.
+ * For example the camera app might be registered as the default handler for
+ * {@link android.provider.MediaStore#INTENT_ACTION_STILL_IMAGE_CAMERA} intent. Subsequently,
+ * if an arbitrary other app requests for a still image camera photo to be taken, the system
+ * will launch the respective default camera app to be launched to handle that request.<br /><br />
+ *
+ * In some cases iorapd might need to know default intents, e.g. for boot-time pinning of
+ * applications that resolve from the default intent. If the application would now be resolved
+ * differently, iorapd would unpin the old application and pin the new application.<br /><br />
+ *
+ * @hide
+ */
+public class AppIntentEvent implements Parcelable {
+
+ /** @see android.content.Intent#CATEGORY_DEFAULT */
+ public static final int TYPE_DEFAULT_INTENT_CHANGED = 0;
+ private static final int TYPE_MAX = 0;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_DEFAULT_INTENT_CHANGED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ @Type public final int type;
+
+ public final ActivityInfo oldActivityInfo;
+ public final ActivityInfo newActivityInfo;
+
+ // TODO: Probably need the corresponding action here as well.
+
+ public static AppIntentEvent createDefaultIntentChanged(ActivityInfo oldActivityInfo,
+ ActivityInfo newActivityInfo) {
+ return new AppIntentEvent(TYPE_DEFAULT_INTENT_CHANGED, oldActivityInfo,
+ newActivityInfo);
+ }
+
+ private AppIntentEvent(@Type int type, ActivityInfo oldActivityInfo,
+ ActivityInfo newActivityInfo) {
+ this.type = type;
+ this.oldActivityInfo = oldActivityInfo;
+ this.newActivityInfo = newActivityInfo;
+
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkTypeInRange(type, TYPE_MAX);
+ Objects.requireNonNull(oldActivityInfo, "oldActivityInfo");
+ Objects.requireNonNull(oldActivityInfo, "newActivityInfo");
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{oldActivityInfo: %s, newActivityInfo: %s}", oldActivityInfo,
+ newActivityInfo);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof AppIntentEvent) {
+ return equals((AppIntentEvent) other);
+ }
+ return false;
+ }
+
+ private boolean equals(AppIntentEvent other) {
+ return type == other.type &&
+ Objects.equals(oldActivityInfo, other.oldActivityInfo) &&
+ Objects.equals(newActivityInfo, other.newActivityInfo);
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(type);
+ oldActivityInfo.writeToParcel(out, flags);
+ newActivityInfo.writeToParcel(out, flags);
+ }
+
+ private AppIntentEvent(Parcel in) {
+ this.type = in.readInt();
+ this.oldActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
+ this.newActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
+
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<AppIntentEvent> CREATOR
+ = new Parcelable.Creator<AppIntentEvent>() {
+ public AppIntentEvent createFromParcel(Parcel in) {
+ return new AppIntentEvent(in);
+ }
+
+ public AppIntentEvent[] newArray(int size) {
+ return new AppIntentEvent[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java b/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java
new file mode 100644
index 0000000..34aedd7
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java
@@ -0,0 +1,46 @@
+/*
+ * 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.google.android.startop.iorap;
+
+/**
+ * Convenience short-hand to throw {@link IllegalAccessException} when the arguments
+ * are out-of-range.
+ */
+public class CheckHelpers {
+ /** @throws IllegalAccessException if {@param type} is not in {@code [0..maxValue]} */
+ public static void checkTypeInRange(int type, int maxValue) {
+ if (type < 0) {
+ throw new IllegalArgumentException(
+ String.format("type must be non-negative (value=%d)", type));
+ }
+ if (type > maxValue) {
+ throw new IllegalArgumentException(
+ String.format("type out of range (value=%d, max=%d)", type, maxValue));
+ }
+ }
+
+ /** @throws IllegalAccessException if {@param state} is not in {@code [0..maxValue]} */
+ public static void checkStateInRange(int state, int maxValue) {
+ if (state < 0) {
+ throw new IllegalArgumentException(
+ String.format("state must be non-negative (value=%d)", state));
+ }
+ if (state > maxValue) {
+ throw new IllegalArgumentException(
+ String.format("state out of range (value=%d, max=%d)", state, maxValue));
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java b/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java
new file mode 100644
index 0000000..aa4eea7
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java
@@ -0,0 +1,131 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.net.Uri;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Forward package manager events to iorapd. <br /><br />
+ *
+ * Knowing when packages are modified by the system are a useful tidbit to help with performance:
+ * for example when a package is replaced, it could be a hint used to invalidate any collected
+ * io profiles used for prefetching or pinning.
+ *
+ * @hide
+ */
+public class PackageEvent implements Parcelable {
+
+ /** @see android.content.Intent#ACTION_PACKAGE_REPLACED */
+ public static final int TYPE_REPLACED = 0;
+ private static final int TYPE_MAX = 0;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_REPLACED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ @Type public final int type;
+
+ /** The path that a package is installed in, for example {@code /data/app/.../base.apk}. */
+ public final Uri packageUri;
+ /** The name of the package, for example {@code com.android.calculator}. */
+ public final String packageName;
+
+ @NonNull
+ public static PackageEvent createReplaced(Uri packageUri, String packageName) {
+ return new PackageEvent(TYPE_REPLACED, packageUri, packageName);
+ }
+
+ private PackageEvent(@Type int type, Uri packageUri, String packageName) {
+ this.type = type;
+ this.packageUri = packageUri;
+ this.packageName = packageName;
+
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkTypeInRange(type, TYPE_MAX);
+ Objects.requireNonNull(packageUri, "packageUri");
+ Objects.requireNonNull(packageName, "packageName");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof PackageEvent) {
+ return equals((PackageEvent) other);
+ }
+ return false;
+ }
+
+ private boolean equals(PackageEvent other) {
+ return type == other.type &&
+ Objects.equals(packageUri, other.packageUri) &&
+ Objects.equals(packageName, other.packageName);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{packageUri: %s, packageName: %s}", packageUri, packageName);
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(type);
+ packageUri.writeToParcel(out, flags);
+ out.writeString(packageName);
+ }
+
+ private PackageEvent(Parcel in) {
+ this.type = in.readInt();
+ this.packageUri = Uri.CREATOR.createFromParcel(in);
+ this.packageName = in.readString();
+
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<PackageEvent> CREATOR
+ = new Parcelable.Creator<PackageEvent>() {
+ public PackageEvent createFromParcel(Parcel in) {
+ return new PackageEvent(in);
+ }
+
+ public PackageEvent[] newArray(int size) {
+ return new PackageEvent[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
new file mode 100644
index 0000000..2c79319
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
@@ -0,0 +1,120 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.NonNull;
+
+/**
+ * Uniquely identify an {@link com.google.android.startop.iorap.IIorap} method invocation,
+ * used for asynchronous callbacks by the server. <br /><br />
+ *
+ * As all system server binder calls must be {@code oneway}, this means all invocations
+ * into {@link com.google.android.startop.iorap.IIorap} are non-blocking. The request ID
+ * exists to associate all calls with their respective callbacks in
+ * {@link com.google.android.startop.iorap.ITaskListener}.
+ *
+ * @see com.google.android.startop.iorap.IIorap
+ *
+ * @hide
+ */
+public class RequestId implements Parcelable {
+
+ public final long requestId;
+
+ private static Object mLock = new Object();
+ private static long mNextRequestId = 0;
+
+ /**
+ * Create a monotonically increasing request ID.<br /><br />
+ *
+ * It is invalid to re-use the same request ID for multiple method calls on
+ * {@link com.google.android.startop.iorap.IIorap}; a new request ID must be created
+ * each time.
+ */
+ @NonNull public static RequestId nextValueForSequence() {
+ long currentRequestId;
+ synchronized (mLock) {
+ currentRequestId = mNextRequestId;
+ ++mNextRequestId;
+ }
+ return new RequestId(currentRequestId);
+ }
+
+ private RequestId(long requestId) {
+ this.requestId = requestId;
+
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ if (requestId < 0) {
+ throw new IllegalArgumentException("request id must be non-negative");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{requestId: %ld}", requestId);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof RequestId) {
+ return equals((RequestId) other);
+ }
+ return false;
+ }
+
+ private boolean equals(RequestId other) {
+ return requestId == other.requestId;
+ }
+
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(requestId);
+ }
+
+ private RequestId(Parcel in) {
+ requestId = in.readLong();
+
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<RequestId> CREATOR
+ = new Parcelable.Creator<RequestId>() {
+ public RequestId createFromParcel(Parcel in) {
+ return new RequestId(in);
+ }
+
+ public RequestId[] newArray(int size) {
+ return new RequestId[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java
new file mode 100644
index 0000000..75d47f9
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java
@@ -0,0 +1,109 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Forward system service events to iorapd.
+ *
+ * @see com.android.server.SystemService
+ *
+ * @hide
+ */
+public class SystemServiceEvent implements Parcelable {
+
+ /** @see com.android.server.SystemService#onBootPhase */
+ public static final int TYPE_BOOT_PHASE = 0;
+ /** @see com.android.server.SystemService#onStart */
+ public static final int TYPE_START = 1;
+ private static final int TYPE_MAX = TYPE_START;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_BOOT_PHASE,
+ TYPE_START,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ @Type public final int type;
+
+ // TODO: do we want to pass the exact build phase enum?
+
+ public SystemServiceEvent(@Type int type) {
+ this.type = type;
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkTypeInRange(type, TYPE_MAX);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{type: %d}", type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof SystemServiceEvent) {
+ return equals((SystemServiceEvent) other);
+ }
+ return false;
+ }
+
+ private boolean equals(SystemServiceEvent other) {
+ return type == other.type;
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(type);
+ }
+
+ private SystemServiceEvent(Parcel in) {
+ this.type = in.readInt();
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<SystemServiceEvent> CREATOR
+ = new Parcelable.Creator<SystemServiceEvent>() {
+ public SystemServiceEvent createFromParcel(Parcel in) {
+ return new SystemServiceEvent(in);
+ }
+
+ public SystemServiceEvent[] newArray(int size) {
+ return new SystemServiceEvent[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java
new file mode 100644
index 0000000..b77c03c
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java
@@ -0,0 +1,127 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Forward user events to iorapd.<br /><br />
+ *
+ * Knowledge of the logged-in user is reserved to be used to set-up appropriate policies
+ * by iorapd (e.g. to handle user default pinned applications changing).
+ *
+ * @see com.android.server.SystemService
+ *
+ * @hide
+ */
+public class SystemServiceUserEvent implements Parcelable {
+
+ /** @see com.android.server.SystemService#onStartUser */
+ public static final int TYPE_START_USER = 0;
+ /** @see com.android.server.SystemService#onUnlockUser */
+ public static final int TYPE_UNLOCK_USER = 1;
+ /** @see com.android.server.SystemService#onSwitchUser*/
+ public static final int TYPE_SWITCH_USER = 2;
+ /** @see com.android.server.SystemService#onStopUser */
+ public static final int TYPE_STOP_USER = 3;
+ /** @see com.android.server.SystemService#onCleanupUser */
+ public static final int TYPE_CLEANUP_USER = 4;
+ private static final int TYPE_MAX = TYPE_CLEANUP_USER;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_START_USER,
+ TYPE_UNLOCK_USER,
+ TYPE_SWITCH_USER,
+ TYPE_STOP_USER,
+ TYPE_CLEANUP_USER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ @Type public final int type;
+ public final int userHandle;
+
+ public SystemServiceUserEvent(@Type int type, int userHandle) {
+ this.type = type;
+ this.userHandle = userHandle;
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkTypeInRange(type, TYPE_MAX);
+ if (userHandle < 0) {
+ throw new IllegalArgumentException("userHandle must be non-negative");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{type: %d, userHandle: %d}", type, userHandle);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof SystemServiceUserEvent) {
+ return equals((SystemServiceUserEvent) other);
+ }
+ return false;
+ }
+
+ private boolean equals(SystemServiceUserEvent other) {
+ return type == other.type &&
+ userHandle == other.userHandle;
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(type);
+ out.writeInt(userHandle);
+ }
+
+ private SystemServiceUserEvent(Parcel in) {
+ this.type = in.readInt();
+ this.userHandle = in.readInt();
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<SystemServiceUserEvent> CREATOR
+ = new Parcelable.Creator<SystemServiceUserEvent>() {
+ public SystemServiceUserEvent createFromParcel(Parcel in) {
+ return new SystemServiceUserEvent(in);
+ }
+
+ public SystemServiceUserEvent[] newArray(int size) {
+ return new SystemServiceUserEvent[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java b/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java
new file mode 100644
index 0000000..b5fd6d8
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java
@@ -0,0 +1,130 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result data accompanying a request for {@link com.google.android.startop.iorap.ITaskListener}
+ * callbacks.<br /><br />
+ *
+ * Following {@link com.google.android.startop.iorap.IIorap} method invocation,
+ * iorapd will issue in-order callbacks for that corresponding {@link RequestId}.<br /><br />
+ *
+ * State transitions are as follows: <br /><br />
+ *
+ * <pre>
+ * ┌─────────────────────────────┐
+ * │ ▼
+ * ┌───────┐ ┌─────────┐ ╔═══════════╗
+ * ──▶ │ BEGAN │ ──▶ │ ONGOING │ ──▶ ║ COMPLETED ║
+ * └───────┘ └─────────┘ ╚═══════════╝
+ * │ │
+ * │ │
+ * ▼ │
+ * ╔═══════╗ │
+ * ──▶ ║ ERROR ║ ◀─────┘
+ * ╚═══════╝
+ *
+ * </pre> <!-- system/iorap/docs/binder/TaskResult.dot -->
+ *
+ * @hide
+ */
+public class TaskResult implements Parcelable {
+
+ public static final int STATE_BEGAN = 0;
+ public static final int STATE_ONGOING = 1;
+ public static final int STATE_COMPLETED = 2;
+ public static final int STATE_ERROR = 3;
+ private static final int STATE_MAX = STATE_ERROR;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "STATE_" }, value = {
+ STATE_BEGAN,
+ STATE_ONGOING,
+ STATE_COMPLETED,
+ STATE_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {}
+
+ @State public final int state;
+
+ @Override
+ public String toString() {
+ return String.format("{state: %d}", state);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (other instanceof TaskResult) {
+ return equals((TaskResult) other);
+ }
+ return false;
+ }
+
+ private boolean equals(TaskResult other) {
+ return state == other.state;
+ }
+
+ public TaskResult(@State int state) {
+ this.state = state;
+
+ checkConstructorArguments();
+ }
+
+ private void checkConstructorArguments() {
+ CheckHelpers.checkStateInRange(state, STATE_MAX);
+ }
+
+ //<editor-fold desc="Binder boilerplate">
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(state);
+ }
+
+ private TaskResult(Parcel in) {
+ state = in.readInt();
+
+ checkConstructorArguments();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<TaskResult> CREATOR
+ = new Parcelable.Creator<TaskResult>() {
+ public TaskResult createFromParcel(Parcel in) {
+ return new TaskResult(in);
+ }
+
+ public TaskResult[] newArray(int size) {
+ return new TaskResult[size];
+ }
+ };
+ //</editor-fold>
+}
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
new file mode 100644
index 0000000..7605784
--- /dev/null
+++ b/startop/iorap/tests/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+// TODO: once b/80095087 is fixed, rewrite this back to android_test
+java_library {
+ name: "libiorap-java-test-lib",
+ srcs: ["src/**/*.kt"],
+
+ static_libs: [
+ // non-test dependencies
+ "libiorap-java",
+ // test android dependencies
+ "platform-test-annotations",
+ "android-support-test",
+ // test framework dependencies
+ "mockito-target-inline-minus-junit4",
+ // "mockito-target-minus-junit4",
+ // Mockito also requires JNI (see Android.mk)
+ // and android:debuggable=true (see AndroidManifest.xml)
+ "truth-prebuilt",
+ ],
+
+ // sdk_version: "current",
+ // certificate: "platform",
+
+ libs: ["android.test.base", "android.test.runner"],
+
+ // test_suites: ["device-tests"],
+}
diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk
new file mode 100644
index 0000000..1b2aa46
--- /dev/null
+++ b/startop/iorap/tests/Android.mk
@@ -0,0 +1,46 @@
+# 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.
+
+# android_test does not support JNI libraries
+# TODO: once b/80095087 is fixed, rewrite this back to android_test
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PACKAGE_NAME := libiorap-java-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ libiorap-java-test-lib
+
+LOCAL_MULTILIB := both
+
+LOCAL_JNI_SHARED_LIBRARIES := \
+ libdexmakerjvmtiagent \
+ libstaticjvmtiagent \
+ libmultiplejvmtiagentsinterferenceagent
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.base \
+ android.test.runner
+
+# Use private APIs
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+include $(BUILD_PACKAGE)
diff --git a/startop/iorap/tests/AndroidManifest.xml b/startop/iorap/tests/AndroidManifest.xml
new file mode 100644
index 0000000..99f4add
--- /dev/null
+++ b/startop/iorap/tests/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!--suppress AndroidUnknownAttribute -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.startop.iorap.tests"
+ android:sharedUserId="com.google.android.startop.iorap.tests"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <!--suppress AndroidDomInspection -->
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.google.android.startop.iorap.tests" />
+
+ <!--
+ 'debuggable=true' is required to properly load mockito jvmti dependencies,
+ otherwise it gives the following error at runtime:
+
+ Openjdkjvmti plugin was loaded on a non-debuggable Runtime.
+ Plugin was loaded too late to change runtime state to DEBUGGABLE. -->
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml
new file mode 100644
index 0000000..f83a16e
--- /dev/null
+++ b/startop/iorap/tests/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs libiorap-java-tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="libiorap-java-tests.apk" />
+ </target_preparer>
+
+ <!--
+ Our IIorapIntegrationTest.kt requires setlinux to be disabled:
+ it connects to the iorapd binder service but this requires selinux permissions:
+
+ avc: denied { find } for service=iorapd pid=2738 uid=10050
+ scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:iorapd_service:s0
+ tclass=service_manager permissive=0
+ -->
+ <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer">
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.google.android.startop.iorap.tests" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
+
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
new file mode 100644
index 0000000..16dcbe2
--- /dev/null
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.google.android.startop.iorap
+
+import android.net.Uri
+import android.os.ServiceManager
+import android.support.test.filters.MediumTest
+import org.junit.Test
+import org.junit.Ignore
+import org.mockito.Mockito.*
+
+// @Ignore("Test is disabled until iorapd is added to init and there's selinux policies for it")
+@MediumTest
+class IIorapIntegrationTest {
+ /**
+ * @throws ServiceManager.ServiceNotFoundException if iorapd service could not be found
+ */
+ private val iorapService : IIorap by lazy {
+ // TODO: connect to 'iorapd.stub' which doesn't actually do any work other than reply.
+ IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"))
+
+ // Use 'adb shell setenforce 0' otherwise this whole test fails,
+ // because the servicemanager is not allowed to hand out the binder token for iorapd.
+
+ // TODO: implement the selinux policies for iorapd.
+ }
+
+ // A dummy binder stub implementation is required to use with mockito#spy.
+ // Mockito overrides the methods at runtime and tracks how methods were invoked.
+ open class DummyTaskListener : ITaskListener.Stub() {
+ // Note: make parameters nullable to avoid the kotlin IllegalStateExceptions
+ // from using the mockito matchers (eq, argThat, etc).
+ override fun onProgress(requestId: RequestId?, result: TaskResult?) {
+ }
+
+ override fun onComplete(requestId: RequestId?, result: TaskResult?) {
+ }
+ }
+
+ private fun testAnyMethod(func : (RequestId) -> Unit) {
+ val taskListener = spy(DummyTaskListener())!!
+
+ try {
+ iorapService.setTaskListener(taskListener)
+ // Note: Binder guarantees total order for oneway messages sent to the same binder
+ // interface, so we don't need any additional blocking here before sending later calls.
+
+ // Every new method call should have a unique request id.
+ val requestId = RequestId.nextValueForSequence()!!
+
+ // Apply the specific function under test.
+ func(requestId)
+
+ // Typical mockito behavior is to allow any-order callbacks, but we want to test order.
+ val inOrder = inOrder(taskListener)
+
+ // The "stub" behavior of iorapd is that every request immediately gets a response of
+ // BEGAN,ONGOING,COMPLETED
+ inOrder.verify(taskListener, timeout(100)).
+ onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN })
+ inOrder.verify(taskListener, timeout(100)).
+ onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING })
+ inOrder.verify(taskListener, timeout(100)).
+ onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED })
+ inOrder.verifyNoMoreInteractions()
+
+ } finally {
+ // iorapService.setTaskListener(null)
+ // FIXME: null is broken, C++ side sees a non-null object.
+ }
+ }
+
+ @Test
+ fun testOnPackageEvent() {
+ /*
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onPackageEvent(requestId,
+ PackageEvent.createReplaced(
+ Uri.parse("https://www.google.com"), "com.fake.package"))
+ }
+ */
+ // FIXME: Broken for some reason. C++ side never sees this call.
+ }
+
+ @Test
+ fun testOnAppIntentEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onAppIntentEvent(requestId, AppIntentEvent.createDefaultIntentChanged(
+ ActivityInfo("dont care", "dont care"),
+ ActivityInfo("dont care 2", "dont care 2")))
+ }
+ }
+
+ @Test
+ fun testOnSystemServiceEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onSystemServiceEvent(requestId,
+ SystemServiceEvent(SystemServiceEvent.TYPE_START))
+ }
+ }
+
+ @Test
+ fun testOnSystemServiceUserEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onSystemServiceUserEvent(requestId,
+ SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER,0))
+ }
+ }
+}
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
new file mode 100644
index 0000000..4abbb3e
--- /dev/null
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
@@ -0,0 +1,140 @@
+/*
+ * 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.google.android.startop.iorap
+
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import android.support.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import com.google.common.truth.Truth.assertThat
+import org.junit.runners.Parameterized
+
+/**
+ * Basic unit tests to ensure that all of the [Parcelable]s in [com.google.android.startop.iorap]
+ * have a valid-conforming interface implementation.
+ */
+@SmallTest
+@RunWith(Parameterized::class)
+class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) {
+ companion object {
+ private val initialRequestId = RequestId.nextValueForSequence()!!
+
+ @JvmStatic
+ @Parameterized.Parameters
+ fun data() = listOf(
+ InputData(
+ newActivityInfo(),
+ newActivityInfo(),
+ ActivityInfo("some package", "some other activity")),
+ InputData(
+ ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
+ ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
+ ActivityHintEvent(ActivityHintEvent.TYPE_POST_COMPLETED,
+ newActivityInfo())),
+ InputData(
+ AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
+ newActivityInfoOther()),
+ AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
+ newActivityInfoOther()),
+ AppIntentEvent.createDefaultIntentChanged(newActivityInfoOther(),
+ newActivityInfo())),
+ InputData(
+ PackageEvent.createReplaced(newUri(), "some package"),
+ PackageEvent.createReplaced(newUri(), "some package"),
+ PackageEvent.createReplaced(newUri(), "some other package")
+ ),
+ InputData(initialRequestId, cloneRequestId(initialRequestId),
+ RequestId.nextValueForSequence()),
+ InputData(
+ SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
+ SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
+ SystemServiceEvent(SystemServiceEvent.TYPE_START)),
+ InputData(
+ SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
+ SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
+ SystemServiceUserEvent(SystemServiceUserEvent.TYPE_CLEANUP_USER, 12345)),
+ InputData(
+ TaskResult(TaskResult.STATE_COMPLETED),
+ TaskResult(TaskResult.STATE_COMPLETED),
+ TaskResult(TaskResult.STATE_ONGOING))
+ )
+
+ private fun newActivityInfo() : ActivityInfo {
+ return ActivityInfo("some package", "some activity")
+ }
+
+ private fun newActivityInfoOther() : ActivityInfo {
+ return ActivityInfo("some package 2", "some activity 2")
+ }
+
+ private fun newUri() : Uri {
+ return Uri.parse("https://www.google.com")
+ }
+
+ private fun cloneRequestId(requestId: RequestId) : RequestId {
+ val constructor = requestId::class.java.declaredConstructors[0]
+ constructor.isAccessible = true
+ return constructor.newInstance(requestId.requestId) as RequestId
+ }
+ }
+
+ /**
+ * Test for [Object.equals] implementation.
+ */
+ @Test
+ fun testEquality() {
+ assertThat(inputData.valid).isEqualTo(inputData.valid)
+ assertThat(inputData.valid).isEqualTo(inputData.validCopy)
+ assertThat(inputData.valid).isNotEqualTo(inputData.validOther)
+ }
+
+ /**
+ * Test for [Parcelable] implementation.
+ */
+ @Test
+ fun testParcelRoundTrip() {
+ // calling writeToParcel and then T::CREATOR.createFromParcel would return the same data.
+ val assertParcels = { it : T, data : InputData<T> ->
+ val parcel = Parcel.obtain()
+ it.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0) // future reads will see all previous writes.
+ assertThat(it).isEqualTo(data.createFromParcel(parcel))
+ parcel.recycle()
+ }
+
+ assertParcels(inputData.valid, inputData)
+ assertParcels(inputData.validCopy, inputData)
+ assertParcels(inputData.validOther, inputData)
+ }
+
+ data class InputData<T : Parcelable>(val valid : T, val validCopy : T, val validOther : T) {
+ val kls = valid.javaClass
+ init {
+ assertThat(valid).isNotSameAs(validCopy)
+ // Don't use isInstanceOf because of phantom warnings in intellij about Class!
+ assertThat(validCopy.javaClass).isEqualTo(valid.javaClass)
+ assertThat(validOther.javaClass).isEqualTo(valid.javaClass)
+ }
+
+ fun createFromParcel(parcel : Parcel) : T {
+ val field = kls.getDeclaredField("CREATOR")
+ val creator = field.get(null) as Parcelable.Creator<T>
+
+ return creator.createFromParcel(parcel)
+ }
+ }
+}
diff --git a/startop/tools/view_compiler/Android.bp b/startop/tools/view_compiler/Android.bp
new file mode 100644
index 0000000..3681529
--- /dev/null
+++ b/startop/tools/view_compiler/Android.bp
@@ -0,0 +1,62 @@
+//
+// 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.
+//
+
+cc_defaults {
+ name: "viewcompiler_defaults",
+ shared_libs: [
+ "libdexfile",
+ "slicer",
+ ],
+}
+
+cc_library_host_static {
+ name: "libviewcompiler",
+ defaults: ["viewcompiler_defaults"],
+ srcs: [
+ "dex_builder.cc",
+ "java_lang_builder.cc",
+ "util.cc",
+ ],
+ static_libs: [
+ "libbase",
+ ],
+}
+
+cc_binary_host {
+ name: "viewcompiler",
+ defaults: ["viewcompiler_defaults"],
+ srcs: [
+ "main.cc",
+ ],
+ static_libs: [
+ "libbase",
+ "libtinyxml2",
+ "libgflags",
+ "libviewcompiler",
+ ],
+}
+
+cc_test_host {
+ name: "view-compiler-tests",
+ defaults: ["viewcompiler_defaults"],
+ srcs: [
+ "dex_builder_test.cc",
+ "util_test.cc",
+ ],
+ static_libs: [
+ "libviewcompiler",
+ ],
+}
diff --git a/startop/tools/view_compiler/README.md b/startop/tools/view_compiler/README.md
new file mode 100644
index 0000000..5659501
--- /dev/null
+++ b/startop/tools/view_compiler/README.md
@@ -0,0 +1,25 @@
+# View Compiler
+
+This directory contains an experimental compiler for layout files.
+
+It will take a layout XML file and produce a CompiledLayout.java file with a
+specialized layout inflation function.
+
+To use it, let's assume you had a layout in `my_layout.xml` and your app was in
+the Java language package `com.example.myapp`. Run the following command:
+
+ viewcompiler my_layout.xml --package com.example.myapp --out CompiledView.java
+
+This will produce a `CompiledView.java`, which can then be compiled into your
+Android app. Then to use it, in places where you would have inflated
+`R.layouts.my_layout`, instead call `CompiledView.inflate`.
+
+Precompiling views like this generally improves the time needed to inflate them.
+
+This tool is still in its early stages and has a number of limitations.
+* Currently only one layout can be compiled at a time.
+* `merge` and `include` nodes are not supported.
+* View compilation is a manual process that requires code changes in the
+ application.
+* This only works for apps that do not use a custom layout inflater.
+* Other limitations yet to be discovered.
diff --git a/startop/tools/view_compiler/TEST_MAPPING b/startop/tools/view_compiler/TEST_MAPPING
new file mode 100644
index 0000000..cc4b17a
--- /dev/null
+++ b/startop/tools/view_compiler/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "view-compiler-tests"
+ }
+ ]
+}
diff --git a/startop/tools/view_compiler/dex_builder.cc b/startop/tools/view_compiler/dex_builder.cc
new file mode 100644
index 0000000..7a9f41f
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_builder.h"
+
+#include "dex/descriptors_names.h"
+#include "dex/dex_instruction.h"
+
+#include <fstream>
+#include <memory>
+
+namespace startop {
+namespace dex {
+
+using std::shared_ptr;
+using std::string;
+
+using art::Instruction;
+using ::dex::kAccPublic;
+
+const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
+const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
+
+namespace {
+// From https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic
+constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00};
+
+// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
+constexpr size_t kMaxEncodedStringLength{5};
+
+} // namespace
+
+void* TrackingAllocator::Allocate(size_t size) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
+ void* raw_buffer = buffer.get();
+ allocations_[raw_buffer] = std::move(buffer);
+ return raw_buffer;
+}
+
+void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
+
+// Write out a DEX file that is basically:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo() { return 5; }
+// }
+void WriteTestDexFile(const string& filename) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
+ cbuilder.set_source_file("dextest.java");
+
+ MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+
+ MethodBuilder::Register r = method.MakeRegister();
+ method.BuildConst4(r, 5);
+ method.BuildReturn(r);
+
+ method.Encode();
+
+ slicer::MemView image{dex_file.CreateImage()};
+
+ std::ofstream out_file(filename);
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
+ dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
+}
+
+slicer::MemView DexBuilder::CreateImage() {
+ ::dex::Writer writer(dex_file_);
+ size_t image_size{0};
+ ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
+ return slicer::MemView{image, image_size};
+}
+
+ir::String* DexBuilder::GetOrAddString(const std::string& string) {
+ ir::String*& entry = strings_[string];
+
+ if (entry == nullptr) {
+ // Need to encode the length and then write out the bytes, including 1 byte for null terminator
+ auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
+ uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
+
+ size_t header_length =
+ reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
+
+ auto end = std::copy(string.begin(), string.end(), string_data_start);
+ *end = '\0';
+
+ entry = Alloc<ir::String>();
+ // +1 for null terminator
+ entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
+ string_data_.push_back(std::move(buffer));
+ }
+ return entry;
+}
+
+ClassBuilder DexBuilder::MakeClass(const std::string& name) {
+ auto* class_def = Alloc<ir::Class>();
+ ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
+ type_def->class_def = class_def;
+
+ class_def->type = type_def;
+ class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
+ class_def->access_flags = kAccPublic;
+ return ClassBuilder{this, class_def};
+}
+
+// TODO(eholk): we probably want GetOrAddString() also
+ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
+ if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
+ return types_by_descriptor_[descriptor];
+ }
+
+ ir::Type* type = Alloc<ir::Type>();
+ type->descriptor = GetOrAddString(descriptor);
+ types_by_descriptor_[descriptor] = type;
+ return type;
+}
+
+ir::Proto* Prototype::Encode(DexBuilder* dex) const {
+ auto* proto = dex->Alloc<ir::Proto>();
+ proto->shorty = dex->GetOrAddString(Shorty());
+ proto->return_type = dex->GetOrAddType(return_type_.descriptor());
+ if (param_types_.size() > 0) {
+ proto->param_types = dex->Alloc<ir::TypeList>();
+ for (const auto& param_type : param_types_) {
+ proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
+ }
+ } else {
+ proto->param_types = nullptr;
+ }
+ return proto;
+}
+
+std::string Prototype::Shorty() const {
+ std::string shorty;
+ shorty.append(return_type_.short_descriptor());
+ for (const auto& type_descriptor : param_types_) {
+ shorty.append(type_descriptor.short_descriptor());
+ }
+ return shorty;
+}
+
+ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def)
+ : parent_(parent), class_(class_def) {}
+
+MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
+ ir::String* dex_name{parent_->GetOrAddString(name)};
+
+ auto* decl = parent_->Alloc<ir::MethodDecl>();
+ decl->name = dex_name;
+ decl->parent = class_->type;
+ decl->prototype = prototype.Encode(parent_);
+
+ return MethodBuilder{parent_, class_, decl};
+}
+
+void ClassBuilder::set_source_file(const string& source) {
+ class_->source_file = parent_->GetOrAddString(source);
+}
+
+MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
+ : dex_{dex}, class_{class_def}, decl_{decl} {}
+
+ir::EncodedMethod* MethodBuilder::Encode() {
+ auto* method = dex_->Alloc<ir::EncodedMethod>();
+ method->decl = decl_;
+
+ // TODO: make access flags configurable
+ method->access_flags = kAccPublic | ::dex::kAccStatic;
+
+ auto* code = dex_->Alloc<ir::Code>();
+ code->registers = num_registers_;
+ // TODO: support ins and outs
+ code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
+ method->code = code;
+
+ class_->direct_methods.push_back(method);
+
+ return method;
+}
+
+MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; }
+
+void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); }
+
+void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); }
+
+void MethodBuilder::BuildConst4(Register target, int value) {
+ DCHECK_LT(value, 16);
+ // TODO: support more registers
+ DCHECK_LT(target, 16);
+ buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8));
+}
+
+} // namespace dex
+} // namespace startop
diff --git a/startop/tools/view_compiler/dex_builder.h b/startop/tools/view_compiler/dex_builder.h
new file mode 100644
index 0000000..d280abc
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.h
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+#ifndef DEX_BUILDER_H_
+#define DEX_BUILDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "slicer/dex_ir.h"
+#include "slicer/writer.h"
+
+namespace startop {
+namespace dex {
+
+// TODO: remove this once the dex generation code is complete.
+void WriteTestDexFile(const std::string& filename);
+
+//////////////////////////
+// Forward declarations //
+//////////////////////////
+class DexBuilder;
+
+// Our custom allocator for dex::Writer
+//
+// This keeps track of all allocations and ensures they are freed when
+// TrackingAllocator is destroyed. Pointers to memory allocated by this
+// allocator must not outlive the allocator.
+class TrackingAllocator : public ::dex::Writer::Allocator {
+ public:
+ virtual void* Allocate(size_t size);
+ virtual void Free(void* ptr);
+
+ private:
+ std::map<void*, std::unique_ptr<uint8_t[]>> allocations_;
+};
+
+// Represents a DEX type descriptor.
+//
+// TODO: add a way to create a descriptor for a reference of a class type.
+class TypeDescriptor {
+ public:
+ // Named constructors for base type descriptors.
+ static const TypeDescriptor Int();
+ static const TypeDescriptor Void();
+
+ // Return the full descriptor, such as I or Ljava/lang/Object
+ const std::string& descriptor() const { return descriptor_; }
+ // Return the shorty descriptor, such as I or L
+ std::string short_descriptor() const { return descriptor().substr(0, 1); }
+
+ private:
+ TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
+
+ const std::string descriptor_;
+};
+
+// Defines a function signature. For example, Prototype{TypeDescriptor::VOID, TypeDescriptor::Int}
+// represents the function type (Int) -> Void.
+class Prototype {
+ public:
+ template <typename... TypeDescriptors>
+ Prototype(TypeDescriptor return_type, TypeDescriptors... param_types)
+ : return_type_{return_type}, param_types_{param_types...} {}
+
+ // Encode this prototype into the dex file.
+ ir::Proto* Encode(DexBuilder* dex) const;
+
+ // Get the shorty descriptor, such as VII for (Int, Int) -> Void
+ std::string Shorty() const;
+
+ private:
+ const TypeDescriptor return_type_;
+ const std::vector<TypeDescriptor> param_types_;
+};
+
+// Tools to help build methods and their bodies.
+class MethodBuilder {
+ public:
+ MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl);
+
+ // Encode the method into DEX format.
+ ir::EncodedMethod* Encode();
+
+ // Registers are just represented by their number.
+ using Register = size_t;
+
+ // Create a new register to be used to storing values. Note that these are not SSA registers, like
+ // might be expected in similar code generators. This does no liveness tracking or anything, so
+ // it's up to the caller to reuse registers as appropriate.
+ Register MakeRegister();
+
+ /////////////////////////////////
+ // Instruction builder methods //
+ /////////////////////////////////
+
+ // return-void
+ void BuildReturn();
+ void BuildReturn(Register src);
+ // const/4
+ void BuildConst4(Register target, int value);
+
+ // TODO: add builders for more instructions
+
+ private:
+ DexBuilder* dex_;
+ ir::Class* class_;
+ ir::MethodDecl* decl_;
+
+ // A buffer to hold instructions we are generating.
+ std::vector<::dex::u2> buffer_;
+
+ // How many registers we've allocated
+ size_t num_registers_;
+};
+
+// A helper to build class definitions.
+class ClassBuilder {
+ public:
+ ClassBuilder(DexBuilder* parent, ir::Class* class_def);
+
+ void set_source_file(const std::string& source);
+
+ // Create a method with the given name and prototype. The returned MethodBuilder can be used to
+ // fill in the method body.
+ MethodBuilder CreateMethod(const std::string& name, Prototype prototype);
+
+ private:
+ DexBuilder* parent_;
+ ir::Class* class_;
+};
+
+// Builds Dex files from scratch.
+class DexBuilder {
+ public:
+ DexBuilder();
+
+ // Create an in-memory image of the DEX file that can either be loaded directly or written to a
+ // file.
+ slicer::MemView CreateImage();
+
+ template <typename T>
+ T* Alloc() {
+ return dex_file_->Alloc<T>();
+ }
+
+ // Find the ir::String that matches the given string, creating it if it does not exist.
+ ir::String* GetOrAddString(const std::string& string);
+ // Create a new class of the given name.
+ ClassBuilder MakeClass(const std::string& name);
+
+ // Add a type for the given descriptor, or return the existing one if it already exists.
+ // See the TypeDescriptor class for help generating these.
+ ir::Type* GetOrAddType(const std::string& descriptor);
+
+ private:
+ std::shared_ptr<ir::DexFile> dex_file_;
+
+ // allocator_ is needed to be able to encode the image.
+ TrackingAllocator allocator_;
+
+ // We'll need to allocate buffers for all of the encoded strings we create. This is where we store
+ // all of them.
+ std::vector<std::unique_ptr<uint8_t[]>> string_data_;
+
+ // Keep track of what types we've defined so we can look them up later.
+ std::map<std::string, ir::Type*> types_by_descriptor_;
+
+ // Keep track of what strings we've defined so we can look them up later.
+ std::map<std::string, ir::String*> strings_;
+};
+
+} // namespace dex
+} // namespace startop
+
+#endif // DEX_BUILDER_H_
diff --git a/startop/tools/view_compiler/dex_builder_test.cc b/startop/tools/view_compiler/dex_builder_test.cc
new file mode 100644
index 0000000..0d8b854
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder_test.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_builder.h"
+
+#include "dex/art_dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "gtest/gtest.h"
+
+using namespace startop::dex;
+
+// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
+// returns whether the verification was successful.
+bool EncodeAndVerify(DexBuilder* dex_file) {
+ slicer::MemView image{dex_file->CreateImage()};
+
+ art::ArtDexFileLoader loader;
+ std::string error_msg;
+ std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
+ image.size(),
+ /*location=*/"",
+ /*location_checksum=*/0,
+ /*oat_dex_file=*/nullptr,
+ /*verify=*/true,
+ /*verify_checksum=*/false,
+ &error_msg)};
+ return loaded_dex_file != nullptr;
+}
+
+TEST(DexBuilderTest, VerifyDexWithClassMethod) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
+ method.BuildReturn();
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
+
+// Makes sure a bad DEX class fails to verify.
+TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ // This method has the error, because methods cannot take Void() as a parameter.
+ auto method{
+ cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
+ method.BuildReturn();
+ method.Encode();
+
+ EXPECT_FALSE(EncodeAndVerify(&dex_file));
+}
+
+TEST(DexBuilderTest, VerifyDexReturn5) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+ auto r = method.MakeRegister();
+ method.BuildConst4(r, 5);
+ method.BuildReturn(r);
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/startop/tools/view_compiler/java_lang_builder.cc b/startop/tools/view_compiler/java_lang_builder.cc
new file mode 100644
index 0000000..0b8754f
--- /dev/null
+++ b/startop/tools/view_compiler/java_lang_builder.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "java_lang_builder.h"
+
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
+using std::string;
+
+void JavaLangViewBuilder::Start() const {
+ out_ << StringPrintf("package %s;\n", package_.c_str())
+ << "import android.content.Context;\n"
+ "import android.content.res.Resources;\n"
+ "import android.content.res.XmlResourceParser;\n"
+ "import android.util.AttributeSet;\n"
+ "import android.util.Xml;\n"
+ "import android.view.*;\n"
+ "import android.widget.*;\n"
+ "\n"
+ "public final class CompiledView {\n"
+ "\n"
+ "static <T extends View> T createView(Context context, AttributeSet attrs, View parent, "
+ "String name, LayoutInflater.Factory factory, LayoutInflater.Factory2 factory2) {"
+ "\n"
+ " if (factory2 != null) {\n"
+ " return (T)factory2.onCreateView(parent, name, context, attrs);\n"
+ " } else if (factory != null) {\n"
+ " return (T)factory.onCreateView(name, context, attrs);\n"
+ " }\n"
+ // TODO: find a way to call the private factory
+ " return null;\n"
+ "}\n"
+ "\n"
+ " public static View inflate(Context context) {\n"
+ " try {\n"
+ " LayoutInflater inflater = LayoutInflater.from(context);\n"
+ " LayoutInflater.Factory factory = inflater.getFactory();\n"
+ " LayoutInflater.Factory2 factory2 = inflater.getFactory2();\n"
+ " Resources res = context.getResources();\n"
+ << StringPrintf(" XmlResourceParser xml = res.getLayout(%s.R.layout.%s);\n",
+ package_.c_str(),
+ layout_name_.c_str())
+ << " AttributeSet attrs = Xml.asAttributeSet(xml);\n"
+ // The Java-language XmlPullParser needs a call to next to find the start document tag.
+ " xml.next(); // start document\n";
+}
+
+void JavaLangViewBuilder::Finish() const {
+ out_ << " } catch (Exception e) {\n"
+ " return null;\n"
+ " }\n" // end try
+ " }\n" // end inflate
+ "}\n"; // end CompiledView
+}
+
+void JavaLangViewBuilder::StartView(const string& class_name) {
+ const string view_var = MakeVar("view");
+ const string layout_var = MakeVar("layout");
+ std::string parent = "null";
+ if (!view_stack_.empty()) {
+ const StackEntry& parent_entry = view_stack_.back();
+ parent = parent_entry.view_var;
+ }
+ out_ << " xml.next(); // <" << class_name << ">\n"
+ << StringPrintf(" %s %s = createView(context, attrs, %s, \"%s\", factory, factory2);\n",
+ class_name.c_str(),
+ view_var.c_str(),
+ parent.c_str(),
+ class_name.c_str())
+ << StringPrintf(" if (%s == null) %s = new %s(context, attrs);\n",
+ view_var.c_str(),
+ view_var.c_str(),
+ class_name.c_str());
+ if (!view_stack_.empty()) {
+ out_ << StringPrintf(" ViewGroup.LayoutParams %s = %s.generateLayoutParams(attrs);\n",
+ layout_var.c_str(),
+ parent.c_str());
+ }
+ view_stack_.push_back({class_name, view_var, layout_var});
+}
+
+void JavaLangViewBuilder::FinishView() {
+ const StackEntry var = view_stack_.back();
+ view_stack_.pop_back();
+ if (!view_stack_.empty()) {
+ const string& parent = view_stack_.back().view_var;
+ out_ << StringPrintf(" xml.next(); // </%s>\n", var.class_name.c_str())
+ << StringPrintf(" %s.addView(%s, %s);\n",
+ parent.c_str(),
+ var.view_var.c_str(),
+ var.layout_params_var.c_str());
+ } else {
+ out_ << StringPrintf(" return %s;\n", var.view_var.c_str());
+ }
+}
+
+const std::string JavaLangViewBuilder::MakeVar(std::string prefix) {
+ std::stringstream v;
+ v << prefix << view_id_++;
+ return v.str();
+}
diff --git a/startop/tools/view_compiler/java_lang_builder.h b/startop/tools/view_compiler/java_lang_builder.h
new file mode 100644
index 0000000..c8d20b2
--- /dev/null
+++ b/startop/tools/view_compiler/java_lang_builder.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef JAVA_LANG_BUILDER_H_
+#define JAVA_LANG_BUILDER_H_
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+// Build Java language code to instantiate views.
+//
+// This has a very small interface to make it easier to generate additional
+// backends, such as a direct-to-DEX version.
+class JavaLangViewBuilder {
+ public:
+ JavaLangViewBuilder(std::string package, std::string layout_name, std::ostream& out = std::cout)
+ : package_(package), layout_name_(layout_name), out_(out) {}
+
+ // Begin generating a class. Adds the package boilerplate, etc.
+ void Start() const;
+ // Finish generating a class, closing off any open curly braces, etc.
+ void Finish() const;
+
+ // Begin creating a view (i.e. process the opening tag)
+ void StartView(const std::string& class_name);
+ // Finish a view, after all of its child nodes have been processed.
+ void FinishView();
+
+ private:
+ const std::string MakeVar(std::string prefix);
+
+ std::string const package_;
+ std::string const layout_name_;
+
+ std::ostream& out_;
+
+ size_t view_id_ = 0;
+
+ struct StackEntry {
+ // The class name for this view object
+ const std::string class_name;
+
+ // The variable name that is holding the view object
+ const std::string view_var;
+
+ // The variable name that holds the object's layout parameters
+ const std::string layout_params_var;
+ };
+ std::vector<StackEntry> view_stack_;
+};
+
+#endif // JAVA_LANG_BUILDER_H_
diff --git a/startop/tools/view_compiler/main.cc b/startop/tools/view_compiler/main.cc
new file mode 100644
index 0000000..7d791c2
--- /dev/null
+++ b/startop/tools/view_compiler/main.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gflags/gflags.h"
+
+#include "dex_builder.h"
+#include "java_lang_builder.h"
+#include "util.h"
+
+#include "tinyxml2.h"
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace {
+
+using namespace tinyxml2;
+using std::string;
+
+constexpr char kStdoutFilename[]{"stdout"};
+
+DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
+DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
+DEFINE_string(package, "", "The package name for the generated class (required)");
+
+class ViewCompilerXmlVisitor : public XMLVisitor {
+ public:
+ ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
+
+ bool VisitEnter(const XMLDocument& /*doc*/) override {
+ builder_->Start();
+ return true;
+ }
+
+ bool VisitExit(const XMLDocument& /*doc*/) override {
+ builder_->Finish();
+ return true;
+ }
+
+ bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override {
+ builder_->StartView(element.Name());
+ return true;
+ }
+
+ bool VisitExit(const XMLElement& /*element*/) override {
+ builder_->FinishView();
+ return true;
+ }
+
+ private:
+ JavaLangViewBuilder* builder_;
+};
+
+} // end namespace
+
+int main(int argc, char** argv) {
+ constexpr size_t kProgramName = 0;
+ constexpr size_t kFileNameParam = 1;
+ constexpr size_t kNumRequiredArgs = 2;
+
+ gflags::SetUsageMessage(
+ "Compile XML layout files into equivalent Java language code\n"
+ "\n"
+ " example usage: viewcompiler layout.xml --package com.example.androidapp");
+ gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);
+
+ gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
+ if (argc != kNumRequiredArgs || cmd.is_default) {
+ gflags::ShowUsageWithFlags(argv[kProgramName]);
+ return 1;
+ }
+
+ if (FLAGS_dex) {
+ startop::dex::WriteTestDexFile("test.dex");
+ return 0;
+ }
+
+ const char* const filename = argv[kFileNameParam];
+ const string layout_name = FindLayoutNameFromFilename(filename);
+
+ // We want to generate Java language code to inflate exactly this layout. This means
+ // generating code to walk the resource XML too.
+
+ XMLDocument xml;
+ xml.LoadFile(filename);
+
+ std::ofstream outfile;
+ if (FLAGS_out != kStdoutFilename) {
+ outfile.open(FLAGS_out);
+ }
+ JavaLangViewBuilder builder{
+ FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile};
+
+ ViewCompilerXmlVisitor visitor{&builder};
+ xml.Accept(&visitor);
+
+ return 0;
+}
diff --git a/startop/tools/view_compiler/util.cc b/startop/tools/view_compiler/util.cc
new file mode 100644
index 0000000..69df41d
--- /dev/null
+++ b/startop/tools/view_compiler/util.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+using std::string;
+
+// TODO: see if we can borrow this from somewhere else, like aapt2.
+string FindLayoutNameFromFilename(const string& filename) {
+ size_t start = filename.rfind("/");
+ if (start == string::npos) {
+ start = 0;
+ } else {
+ start++; // advance past '/' character
+ }
+ size_t end = filename.find(".", start);
+
+ return filename.substr(start, end - start);
+}
diff --git a/startop/tools/view_compiler/util.h b/startop/tools/view_compiler/util.h
new file mode 100644
index 0000000..03e0939
--- /dev/null
+++ b/startop/tools/view_compiler/util.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <string>
+
+std::string FindLayoutNameFromFilename(const std::string& filename);
+
+#endif // UTIL_H_
diff --git a/startop/tools/view_compiler/util_test.cc b/startop/tools/view_compiler/util_test.cc
new file mode 100644
index 0000000..d1540d3
--- /dev/null
+++ b/startop/tools/view_compiler/util_test.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+#include "gtest/gtest.h"
+
+using std::string;
+
+TEST(UtilTest, FindLayoutNameFromFilename) {
+ EXPECT_EQ("bar", ::FindLayoutNameFromFilename("foo/bar.xml"));
+ EXPECT_EQ("bar", ::FindLayoutNameFromFilename("bar.xml"));
+ EXPECT_EQ("bar", ::FindLayoutNameFromFilename("./foo/bar.xml"));
+ EXPECT_EQ("bar", ::FindLayoutNameFromFilename("/foo/bar.xml"));
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 096cf37..daa09f5 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -141,6 +141,8 @@
* The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to
* Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_REQUEST_HANDOVER =
"android.telecom.event.REQUEST_HANDOVER";
@@ -149,6 +151,8 @@
* Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event. Specifies the
* {@link PhoneAccountHandle} to which a call should be handed over to.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE =
"android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE";
@@ -161,6 +165,8 @@
* {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and
* {@link VideoProfile#STATE_TX_ENABLED}.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_VIDEO_STATE =
"android.telecom.extra.HANDOVER_VIDEO_STATE";
@@ -176,6 +182,8 @@
* {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
* is called to initate the handover.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS";
@@ -186,6 +194,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_COMPLETE =
"android.telecom.event.HANDOVER_COMPLETE";
@@ -198,6 +208,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED =
"android.telecom.event.HANDOVER_SOURCE_DISCONNECTED";
@@ -209,6 +221,8 @@
* <p>
* A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
@@ -383,7 +397,19 @@
public static final int PROPERTY_WIFI = 0x00000008;
/**
- * Call is using high definition audio.
+ * When set, the UI should indicate to the user that a call is using high definition
+ * audio.
+ * <p>
+ * The underlying {@link ConnectionService} is responsible for reporting this
+ * property. It is important to note that this property is not intended to report the
+ * actual audio codec being used for a Call, but whether the call should be indicated
+ * to the user as high definition.
+ * <p>
+ * The Android Telephony stack reports this property for calls based on a number
+ * of factors, including which audio codec is used and whether a call is using an HD
+ * codec end-to-end. Some mobile operators choose to suppress display of an HD indication,
+ * and in these cases this property will not be set for a call even if the underlying audio
+ * codec is in fact "high definition".
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
@@ -434,8 +460,15 @@
*/
public static final int PROPERTY_RTT = 0x00000400;
+ /**
+ * Indicates that the call has been identified as the network as an emergency call. This
+ * property may be set for both incoming and outgoing calls which the network identifies as
+ * emergency calls.
+ */
+ public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000800
+ // Next PROPERTY value: 0x00001000
//******************************************************************************************
private final String mTelecomCallId;
@@ -601,6 +634,9 @@
if(hasProperty(properties, PROPERTY_ASSISTED_DIALING_USED)) {
builder.append(" PROPERTY_ASSISTED_DIALING_USED");
}
+ if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+ builder.append(" PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL");
+ }
builder.append("]");
return builder.toString();
}
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 9c874bf..b906d0b 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -63,6 +63,10 @@
/**
* Telecom calls this method to inform the implemented {@link CallRedirectionService} of
* a new outgoing call which is being placed.
+ *
+ * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+ * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+ *
* @param handle the phone number dialed by the user
* @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
*/
@@ -72,6 +76,9 @@
* The implemented {@link CallRedirectionService} calls this method to response a request
* received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
* are required to the outgoing call, and that the call should be placed as-is.
+ *
+ * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ *
*/
public final void placeCallUnmodified() {
try {
@@ -84,6 +91,9 @@
* The implemented {@link CallRedirectionService} calls this method to response a request
* received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
* are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+ *
+ * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ *
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
* If {@code null}, no change will be made to the
@@ -100,6 +110,9 @@
* The implemented {@link CallRedirectionService} calls this method to response a request
* received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
* call should be canceled entirely.
+ *
+ * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ *
*/
public final void cancelCall() {
try {
@@ -144,7 +157,6 @@
@Override
public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
PhoneAccountHandle targetPhoneAccount) {
- Log.v(this, "placeCall");
SomeArgs args = SomeArgs.obtain();
args.arg1 = adapter;
args.arg2 = handle;
@@ -154,14 +166,12 @@
}
@Override
- public IBinder onBind(Intent intent) {
- Log.v(this, "onBind");
+ public final IBinder onBind(Intent intent) {
return new CallRedirectionBinder();
}
@Override
- public boolean onUnbind(Intent intent) {
- Log.v(this, "onUnbind");
+ public final boolean onUnbind(Intent intent) {
return false;
}
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 024bd30..a39e885 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -22,6 +22,8 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.telecom.Connection.VideoProvider;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import java.util.ArrayList;
@@ -573,6 +575,20 @@
}
/**
+ * Updates RIL voice radio technology used for current conference after its creation.
+ *
+ * @hide
+ */
+ public void updateCallRadioTechAfterCreation() {
+ final Connection primaryConnection = getPrimaryConnection();
+ if (primaryConnection != null) {
+ setCallRadioTech(primaryConnection.getCallRadioTech());
+ } else {
+ Log.w(this, "No primary connection found while updateCallRadioTechAfterCreation");
+ }
+ }
+
+ /**
* @hide
* @deprecated Use {@link #setConnectionTime}.
*/
@@ -652,6 +668,37 @@
}
/**
+ * Sets RIL voice radio technology used for current conference.
+ *
+ * @param vrat the RIL voice radio technology used for current conference,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+ putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ ServiceState.rilRadioTechnologyToNetworkType(vrat));
+ }
+
+ /**
+ * Returns RIL voice radio technology used for current conference.
+ *
+ * @return the RIL voice radio technology used for current conference,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+ int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ Bundle extras = getExtras();
+ if (extras != null) {
+ voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+ return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+ }
+
+ /**
* Inform this Conference that the state of its audio output has been changed externally.
*
* @param state The new audio state.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 5d5b15d..ee1ca5f 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -38,6 +38,8 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.view.Surface;
@@ -411,6 +413,13 @@
*/
public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
+ /**
+ * Set by the framework to indicate that the network has identified a Connection as an emergency
+ * call.
+ * @hide
+ */
+ public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1 << 10;
+
//**********************************************************************************************
// Next PROPERTY value: 1<<10
//**********************************************************************************************
@@ -584,6 +593,8 @@
* {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has
* successfully completed.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_COMPLETE =
"android.telecom.event.HANDOVER_COMPLETE";
@@ -593,6 +604,8 @@
* {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed
* to complete.
* @hide
+ * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+ * APIs instead.
*/
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
@@ -800,6 +813,10 @@
builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
}
+ if (can(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+ builder.append(isLong ? " PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL" : " ecall");
+ }
+
builder.append("]");
return builder.toString();
}
@@ -1879,6 +1896,24 @@
}
/**
+ * Returns RIL voice radio technology used for current connection.
+ *
+ * @return the RIL voice radio technology used for current connection,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+ int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ Bundle extras = getExtras();
+ if (extras != null) {
+ voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+ return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+ }
+
+ /**
* @return The status hints for this connection.
*/
public final StatusHints getStatusHints() {
@@ -2312,6 +2347,26 @@
}
/**
+ * Sets RIL voice radio technology used for current connection.
+ *
+ * @param vrat the RIL Voice Radio Technology used for current connection,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+ putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ ServiceState.rilRadioTechnologyToNetworkType(vrat));
+ // Propagates the call radio technology to its parent {@link android.telecom.Conference}
+ // This action only covers non-IMS CS conference calls.
+ // For IMS PS call conference call, it can be updated via its host connection
+ // {@link #Listener.onExtrasChanged} event.
+ if (getConference() != null) {
+ getConference().setCallRadioTech(vrat);
+ }
+ }
+
+ /**
* Sets the label and icon status to display in the in-call UI.
*
* @param statusHints The status label and icon to set.
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index 383d10b..bb066ad 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -195,6 +195,8 @@
public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
public static final int FILTERING_COMPLETED_TIMING = 10;
public static final int FILTERING_TIMED_OUT_TIMING = 11;
+ /** {@hide} */
+ public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12;
public static final int INVALID = 999999;
@@ -256,6 +258,27 @@
public static final int SIP_PHONE = 0x8;
public static final int THIRD_PARTY_PHONE = 0x10;
+ /**
+ * Indicating the call source is not specified.
+ *
+ * @hide
+ */
+ public static final int CALL_SOURCE_UNSPECIFIED = 0;
+
+ /**
+ * Indicating the call is initiated via emergency dialer's dialpad.
+ *
+ * @hide
+ */
+ public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1;
+
+ /**
+ * Indicating the call is initiated via emergency dialer's shortcut button.
+ *
+ * @hide
+ */
+ public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2;
+
public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
public static final long MILLIS_IN_1_SECOND = 1000;
@@ -319,6 +342,9 @@
// A list of video events that have occurred.
private List<VideoEvent> videoEvents;
+ // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants.
+ private int callSource = CALL_SOURCE_UNSPECIFIED;
+
public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
int callTerminationCode, boolean isEmergencyCall, String connectionService,
@@ -356,6 +382,7 @@
isVideoCall = readByteAsBoolean(in);
videoEvents = new LinkedList<>();
in.readTypedList(videoEvents, VideoEvent.CREATOR);
+ callSource = in.readInt();
}
public void writeToParcel(Parcel out, int flags) {
@@ -373,6 +400,7 @@
out.writeTypedList(eventTimings);
writeBooleanAsByte(out, isVideoCall);
out.writeTypedList(videoEvents);
+ out.writeInt(callSource);
}
/** {@hide} */
@@ -385,6 +413,11 @@
this.videoEvents = videoEvents;
}
+ /** {@hide} */
+ public void setCallSource(int callSource) {
+ this.callSource = callSource;
+ }
+
public long getStartTimeMillis() {
return startTimeMillis;
}
@@ -443,6 +476,11 @@
return videoEvents;
}
+ /** {@hide} */
+ public int getCallSource() {
+ return callSource;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 48c1e24..3127b35 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,15 @@
"android.telecom.extra.CALL_TECHNOLOGY_TYPE";
/**
+ * Optional extra for communicating the call network technology used by a
+ * {@link android.telecom.Connection} to Telecom and InCallUI.
+ *
+ * @see {@code NETWORK_TYPE_*} in {@link android.telephony.TelephonyManager}.
+ */
+ public static final String EXTRA_CALL_NETWORK_TYPE =
+ "android.telecom.extra.CALL_NETWORK_TYPE";
+
+ /**
* An optional {@link android.content.Intent#ACTION_CALL} intent extra denoting the
* package name of the app specifying an alternative gateway for the call.
* The value is a string.
@@ -622,6 +631,18 @@
"android.telecom.extra.USE_ASSISTED_DIALING";
/**
+ * Optional extra for {@link #placeCall(Uri, Bundle)} containing an integer that specifies
+ * the source where user initiated this call. This data is used in metrics.
+ * Valid source are:
+ * {@link ParcelableCallAnalytics#CALL_SOURCE_UNSPECIFIED},
+ * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_DIALPAD},
+ * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_SHORTCUT}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+
+ /**
* The following 4 constants define how properties such as phone numbers and names are
* displayed to the user.
*/
@@ -655,7 +676,7 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelecomManager from(Context context) {
return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
}
@@ -1863,6 +1884,43 @@
}
}
+ /**
+ * Determines if there is an ongoing emergency call. This can be either an outgoing emergency
+ * call, as identified by the dialed number, or because a call was identified by the network
+ * as an emergency call.
+ * @return {@code true} if there is an ongoing emergency call, {@code false} otherwise.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean isInEmergencyCall() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecomService().isInEmergencyCall();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException isInEmergencyCall: " + e);
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
+ * @param intent The {@link Intent#ACTION_CALL} intent to handle.
+ * @hide
+ */
+ public void handleCallIntent(Intent intent) {
+ try {
+ if (isServiceConnected()) {
+ getTelecomService().handleCallIntent(intent);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException handleCallIntent: " + e);
+ }
+
+ }
+
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
return mTelecomServiceOverride;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index b4e7d56..df7d683 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -279,4 +279,14 @@
* @see TelecomServiceImpl#acceptHandover
*/
void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
+
+ /**
+ * @see TelecomServiceImpl#isInEmergencyCall
+ */
+ boolean isInEmergencyCall();
+
+ /**
+ * @see TelecomServiceImpl#handleCallIntent
+ */
+ void handleCallIntent(in Intent intent);
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 7e63230..d48f21b 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3213,7 +3213,6 @@
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
return values;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9319750..149ccf0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -271,6 +271,14 @@
KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
/**
+ * Do only allow auto selection in Advanced Network Settings when in home network.
+ * Manual selection is allowed when in roaming network.
+ * @hide
+ */
+ public static final String
+ KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
+
+ /**
* Control whether users receive a simplified network settings UI and improved network
* selection.
*/
@@ -1070,6 +1078,16 @@
/**
* Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+ *
+ * <p>Available options are:
+ * <ul>
+ * <li> 0: %s</li>
+ * <li> 1: %s Wi-Fi Calling</li>
+ * <li> 2: WLAN Call</li>
+ * <li> 3: %s WLAN Call</li>
+ * <li> 4: %s Wi-Fi</li>
+ * <li> 5: WiFi Calling | %s</li>
+ * <li> 6: %s VoWifi</li>
* @hide
*/
public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
@@ -1077,6 +1095,15 @@
public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
/**
+ * Use root locale when reading wfcSpnFormats.
+ *
+ * If true, then the root locale will always be used when reading wfcSpnFormats. This means the
+ * non localized version of wfcSpnFormats will be used.
+ * @hide
+ */
+ public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale";
+
+ /**
* The Component Name of the activity that can setup the emergency addrees for WiFi Calling
* as per carrier requirement.
* @hide
@@ -1606,11 +1633,21 @@
* When {@code false}, use default title for Enhanced 4G LTE Mode settings.
* When {@code true}, use the variant.
* @hide
+ * @deprecated use {@link #KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT}.
*/
+ @Deprecated
public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL =
"enhanced_4g_lte_title_variant_bool";
/**
+ * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings.
+ * Default value is 0, which indicates the default title string.
+ * @hide
+ */
+ public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT =
+ "enhanced_4g_lte_title_variant_int";
+
+ /**
* Indicates whether the carrier wants to notify the user when handover of an LTE video call to
* WIFI fails.
* <p>
@@ -1928,6 +1965,31 @@
public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
/**
+ * Indicates if the carrier supports auto-upgrading a call to RTT when receiving a call from a
+ * RTT-supported device.
+ * @hide
+ */
+ public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
+
+ /**
+ * Indicates if the carrier supports RTT during a video call.
+ * @hide
+ */
+ public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+
+ /**
+ * Indicates if the carrier supports upgrading a voice call to an RTT call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
+
+ /**
+ * Indicates if the carrier supports downgrading a RTT call to a voice call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
+
+ /**
* The flag to disable the popup dialog which warns the user of data charges.
* @hide
*/
@@ -1947,6 +2009,17 @@
"skip_cf_fail_to_disable_dialog_bool";
/**
+ * Flag specifying whether operator supports including no reply condition timer option on
+ * CFNRy (3GPP TS 24.082 3: Call Forwarding on No Reply) in the call forwarding settings UI.
+ * {@code true} - include no reply condition timer option on CFNRy
+ * {@code false} - don't include no reply condition timer option on CFNRy
+ *
+ * @hide
+ */
+ public static final String KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL =
+ "support_no_reply_timer_for_cfnry_bool";
+
+ /**
* List of the FAC (feature access codes) to dial as a normal call.
* @hide
*/
@@ -2086,6 +2159,16 @@
public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
"call_redirection_service_component_name_string";
+ /**
+ * Flag specifying whether to show notification(call blocking disabled) when Enhanced Call
+ * Blocking(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL) is enabled and making emergency call.
+ * When true, notification is shown always.
+ * When false, notification is shown only when any setting of "Enhanced Blocked number" is
+ * enabled.
+ */
+ public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL =
+ "show_call_blocking_disabled_notification_always_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -2142,6 +2225,7 @@
sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ sDefaults.putBoolean(KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false);
sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
@@ -2264,6 +2348,7 @@
sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
+ sDefaults.putBoolean(KEY_WFC_SPN_USE_ROOT_LOCALE, false);
sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, "");
sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
sDefaults.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, false);
@@ -2273,7 +2358,7 @@
sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
- sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, true);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -2370,6 +2455,7 @@
sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
+ sDefaults.putInt(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 0);
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
@@ -2399,6 +2485,7 @@
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false);
@@ -2422,6 +2509,7 @@
});
sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
+ sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index ee5cdc2..d7169b2 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -319,6 +319,29 @@
*/
public static final int IMS_SIP_ALTERNATE_EMERGENCY_CALL = 71;
+ /**
+ * Indicates that a new outgoing call cannot be placed because there is already an outgoing
+ * call dialing out.
+ */
+ public static final int ALREADY_DIALING = 72;
+
+ /**
+ * Indicates that a new outgoing call cannot be placed while there is a ringing call.
+ */
+ public static final int CANT_CALL_WHILE_RINGING = 73;
+
+ /**
+ * Indicates that a new outgoing call cannot be placed because calling has been disabled using
+ * the ro.telephony.disable-call system property.
+ */
+ public static final int CALLING_DISABLED = 74;
+
+ /**
+ * Indicates that a new outgoing call cannot be placed because there is currently an ongoing
+ * foreground and background call.
+ */
+ public static final int TOO_MANY_ONGOING_CALLS = 75;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -474,6 +497,14 @@
return "NORMAL_UNSPECIFIED";
case IMS_SIP_ALTERNATE_EMERGENCY_CALL:
return "IMS_SIP_ALTERNATE_EMERGENCY_CALL";
+ case ALREADY_DIALING:
+ return "ALREADY_DIALING";
+ case CANT_CALL_WHILE_RINGING:
+ return "CANT_CALL_WHILE_RINGING";
+ case CALLING_DISABLED:
+ return "CALLING_DISABLED";
+ case TOO_MANY_ONGOING_CALLS:
+ return "TOO_MANY_ONGOING_CALLS";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java
new file mode 100644
index 0000000..e373797
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsGroupCallSession.java
@@ -0,0 +1,300 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCall;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.InternalGroupCallCallback;
+import android.telephony.mbms.InternalGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsUtils;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This class provides functionality for accessing group call functionality over MBMS.
+ */
+public class MbmsGroupCallSession implements AutoCloseable {
+ private static final String LOG_TAG = "MbmsGroupCallSession";
+
+ /**
+ * Service action which must be handled by the middleware implementing the MBMS group call
+ * interface.
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String MBMS_GROUP_CALL_SERVICE_ACTION =
+ "android.telephony.action.EmbmsGroupCall";
+
+ /**
+ * Metadata key that specifies the component name of the service to bind to for group calls.
+ * @hide
+ */
+ @TestApi
+ public static final String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA =
+ "mbms-group-call-service-override";
+
+ private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
+
+ private AtomicReference<IMbmsGroupCallService> mService = new AtomicReference<>(null);
+ private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ sIsInitialized.set(false);
+ mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ "Received death notification");
+ }
+ };
+
+ private InternalGroupCallSessionCallback mInternalCallback;
+ private Set<GroupCall> mKnownActiveGroupCalls = new ArraySet<>();
+
+ private final Context mContext;
+ private int mSubscriptionId;
+
+ /** @hide */
+ private MbmsGroupCallSession(Context context, Executor executor, int subscriptionId,
+ MbmsGroupCallSessionCallback callback) {
+ mContext = context;
+ mSubscriptionId = subscriptionId;
+ mInternalCallback = new InternalGroupCallSessionCallback(callback, executor);
+ }
+
+ /**
+ * Create a new {@link MbmsGroupCallSession} using the given subscription ID.
+ *
+ * You may only have one instance of {@link MbmsGroupCallSession} per UID. If you call this
+ * method while there is an active instance of {@link MbmsGroupCallSession} in your process
+ * (in other words, one that has not had {@link #close()} called on it), this method will
+ * throw an {@link IllegalStateException}. If you call this method in a different process
+ * running under the same UID, an error will be indicated via
+ * {@link MbmsGroupCallSessionCallback#onError(int, String)}.
+ *
+ * Note that initialization may fail asynchronously. If you wish to try again after you
+ * receive such an asynchronous error, you must call {@link #close()} on the instance of
+ * {@link MbmsGroupCallSession} that you received before calling this method again.
+ *
+ * @param context The {@link Context} to use.
+ * @param executor The executor on which you wish to execute callbacks.
+ * @param subscriptionId The subscription ID to use.
+ * @param callback A callback object on which you wish to receive results of asynchronous
+ * operations.
+ * @return An instance of {@link MbmsGroupCallSession}, or null if an error occurred.
+ */
+ public static @Nullable MbmsGroupCallSession create(@NonNull Context context,
+ @NonNull Executor executor, int subscriptionId,
+ final @NonNull MbmsGroupCallSessionCallback callback) {
+ if (!sIsInitialized.compareAndSet(false, true)) {
+ throw new IllegalStateException("Cannot create two instances of MbmsGroupCallSession");
+ }
+ MbmsGroupCallSession session = new MbmsGroupCallSession(context, executor,
+ subscriptionId, callback);
+
+ final int result = session.bindAndInitialize();
+ if (result != MbmsErrors.SUCCESS) {
+ sIsInitialized.set(false);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(result, null);
+ }
+ });
+ return null;
+ }
+ return session;
+ }
+
+ /**
+ * Create a new {@link MbmsGroupCallSession} using the system default data subscription ID.
+ * See {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ */
+ public static MbmsGroupCallSession create(@NonNull Context context,
+ @NonNull Executor executor, @NonNull MbmsGroupCallSessionCallback callback) {
+ return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
+ }
+
+ /**
+ * Terminates this instance. Also terminates
+ * any group calls spawned from this instance as if
+ * {@link GroupCall#close()} had been called on them. After this method returns,
+ * no further callbacks originating from the middleware will be enqueued on the provided
+ * instance of {@link MbmsGroupCallSessionCallback}, but callbacks that have already been
+ * enqueued will still be delivered.
+ *
+ * It is safe to call {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)} to
+ * obtain another instance of {@link MbmsGroupCallSession} immediately after this method
+ * returns.
+ *
+ * May throw an {@link IllegalStateException}
+ */
+ public void close() {
+ try {
+ IMbmsGroupCallService groupCallService = mService.get();
+ if (groupCallService == null) {
+ // Ignore and return, assume already disposed.
+ return;
+ }
+ groupCallService.dispose(mSubscriptionId);
+ for (GroupCall s : mKnownActiveGroupCalls) {
+ s.getCallback().stop();
+ }
+ mKnownActiveGroupCalls.clear();
+ } catch (RemoteException e) {
+ // Ignore for now
+ } finally {
+ mService.set(null);
+ sIsInitialized.set(false);
+ mInternalCallback.stop();
+ }
+ }
+
+ /**
+ * Starts the requested group call, reporting status to the indicated callback.
+ * Returns an object used to control that call.
+ *
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
+ * Asynchronous errors through the callback include any of the errors in
+ * {@link MbmsErrors.GeneralErrors}.
+ *
+ * @param executor The executor on which you wish to execute callbacks for this stream.
+ * @param tmgi The TMGI, an identifier for the group call you want to join.
+ * @param saiArray An array of SAIs for the group call that should be negotiated separately with
+ * the carrier.
+ * @param frequencyArray An array of frequencies for the group call that should be negotiated
+ * separately with the carrier.
+ * @param callback The callback that you want to receive information about the call on.
+ * @return An instance of {@link GroupCall} through which the call can be controlled.
+ * May be {@code null} if an error occurred.
+ */
+ public @Nullable GroupCall startGroupCall(@NonNull Executor executor, long tmgi, int[] saiArray,
+ int[] frequencyArray, @NonNull GroupCallCallback callback) {
+ IMbmsGroupCallService groupCallService = mService.get();
+ if (groupCallService == null) {
+ throw new IllegalStateException("Middleware not yet bound");
+ }
+
+ InternalGroupCallCallback serviceCallback = new InternalGroupCallCallback(
+ callback, executor);
+
+ GroupCall serviceForApp = new GroupCall(mSubscriptionId,
+ groupCallService, this, tmgi, serviceCallback);
+ mKnownActiveGroupCalls.add(serviceForApp);
+
+ try {
+ int returnCode = groupCallService.startGroupCall(
+ mSubscriptionId, tmgi, saiArray, frequencyArray, serviceCallback);
+ if (returnCode == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
+ if (returnCode != MbmsErrors.SUCCESS) {
+ mInternalCallback.onError(returnCode, null);
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Remote process died");
+ mService.set(null);
+ sIsInitialized.set(false);
+ mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return null;
+ }
+
+ return serviceForApp;
+ }
+
+ /** @hide */
+ public void onGroupCallStopped(GroupCall service) {
+ mKnownActiveGroupCalls.remove(service);
+ }
+
+ private int bindAndInitialize() {
+ return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION,
+ new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IMbmsGroupCallService groupCallService =
+ IMbmsGroupCallService.Stub.asInterface(service);
+ int result;
+ try {
+ result = groupCallService.initialize(mInternalCallback,
+ mSubscriptionId);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Service died before initialization");
+ mInternalCallback.onError(
+ MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+ e.toString());
+ sIsInitialized.set(false);
+ return;
+ } catch (RuntimeException e) {
+ Log.e(LOG_TAG, "Runtime exception during initialization");
+ mInternalCallback.onError(
+ MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+ e.toString());
+ sIsInitialized.set(false);
+ return;
+ }
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return"
+ + " an unknown error code");
+ }
+ if (result != MbmsErrors.SUCCESS) {
+ mInternalCallback.onError(result,
+ "Error returned during initialization");
+ sIsInitialized.set(false);
+ return;
+ }
+ try {
+ groupCallService.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ "Middleware lost during initialization");
+ sIsInitialized.set(false);
+ return;
+ }
+ mService.set(groupCallService);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ sIsInitialized.set(false);
+ mService.set(null);
+ }
+ });
+ }
+}
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 8e99518..ac38efb 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -32,7 +32,12 @@
/**
* Represents the neighboring cell information, including
* Received Signal Strength and Cell ID location.
+ *
+ * @deprecated This class should not be used by any app targeting
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} or higher. Instead callers should use
+ * {@link android.telephony.CellInfo CellInfo}.
*/
+@Deprecated
public class NeighboringCellInfo implements Parcelable
{
/**
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index c393155..b312f84 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -95,6 +95,13 @@
@RegState
private final int mRegState;
+ /**
+ * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
+ * from resource overlay or carrier config.
+ */
+ @ServiceState.RoamingType
+ private int mRoamingType;
+
private final int mAccessNetworkTechnology;
private final int mRejectCause;
@@ -140,6 +147,8 @@
mDomain = domain;
mTransportType = transportType;
mRegState = regState;
+ mRoamingType = (regState == REG_STATE_ROAMING)
+ ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
mAccessNetworkTechnology = accessNetworkTechnology;
mRejectCause = rejectCause;
mAvailableServices = availableServices;
@@ -182,6 +191,7 @@
mDomain = source.readInt();
mTransportType = source.readInt();
mRegState = source.readInt();
+ mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
mEmergencyOnly = source.readBoolean();
@@ -211,6 +221,31 @@
}
/**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
+ public boolean isRoaming() {
+ return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
+ }
+
+ /**
+ * Set {@link ServiceState.RoamingType roaming type}. This could override
+ * roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public void setRoamingType(@ServiceState.RoamingType int roamingType) {
+ mRoamingType = roamingType;
+ }
+
+ /**
+ * @return {@link ServiceState.RoamingType roaming type}. This could return
+ * overridden roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public @ServiceState.RoamingType int getRoamingType() {
+ return mRoamingType;
+ }
+
+ /**
* @return Whether emergency is enabled.
*/
public boolean isEmergencyEnabled() { return mEmergencyOnly; }
@@ -280,6 +315,7 @@
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
.append("transportType=").append(mTransportType)
.append(" regState=").append(regStateToString(mRegState))
+ .append(" roamingType=").append(mRoamingType)
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
@@ -293,9 +329,9 @@
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegState, mAccessNetworkTechnology,
- mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity,
- mVoiceSpecificStates, mDataSpecificStates);
+ return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+ mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
+ mCellIdentity, mVoiceSpecificStates, mDataSpecificStates);
}
@Override
@@ -310,6 +346,7 @@
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegState == other.mRegState
+ && mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
@@ -325,6 +362,7 @@
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegState);
+ dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
dest.writeBoolean(mEmergencyOnly);
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 7c7d7a0..202da68 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -16,11 +16,10 @@
package android.telephony;
+import android.annotation.IntDef;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.annotation.IntDef;
-import android.util.Log;
import com.android.internal.telephony.ITelephony;
@@ -113,6 +112,8 @@
}
try {
telephony.stopNetworkScan(mSubId, mScanId);
+ } catch (IllegalArgumentException ex) {
+ Rlog.d(TAG, "stopNetworkScan - no active scan for ScanID=" + mScanId);
} catch (RemoteException ex) {
Rlog.e(TAG, "stopNetworkScan RemoteException", ex);
} catch (RuntimeException ex) {
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index bd6a59d..284e998 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -17,12 +17,14 @@
package android.telephony;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IPhoneStateListener;
import java.lang.ref.WeakReference;
@@ -280,6 +282,15 @@
*/
public static final int LISTEN_PHONE_CAPABILITY_CHANGE = 0x00200000;
+ /**
+ * Listen for changes to the radio power state.
+ *
+ * @see #onRadioPowerStateChanged
+ * @hide
+ */
+ @SystemApi
+ public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 0x00400000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -406,6 +417,9 @@
PhoneStateListener.this.onPhoneCapabilityChanged(
(PhoneCapability) msg.obj);
break;
+ case LISTEN_RADIO_POWER_STATE_CHANGED:
+ PhoneStateListener.this.onRadioPowerStateChanged((int) msg.obj);
+ break;
}
}
};
@@ -646,6 +660,18 @@
}
/**
+ * Callback invoked when modem radio power state changes. Requires
+ * the READ_PRIVILEGED_PHONE_STATE permission.
+ * @param state the modem radio power state
+ * @hide
+ */
+ @SystemApi
+ public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ // default implementation empty
+ }
+
+
+ /**
* Callback invoked when telephony has received notice from a carrier
* app that a network action that could result in connectivity loss
* has been requested by an app using
@@ -776,10 +802,18 @@
public void onPhoneCapabilityChanged(PhoneCapability capability) {
send(LISTEN_PHONE_CAPABILITY_CHANGE, 0, 0, capability);
}
+
+ public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ send(LISTEN_RADIO_POWER_STATE_CHANGED, 0, 0, state);
+ }
}
+ /**
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@UnsupportedAppUsage
- IPhoneStateListener callback = new IPhoneStateListenerStub(this);
+ public final IPhoneStateListener callback = new IPhoneStateListenerStub(this);
private void log(String s) {
Rlog.d(LOG_TAG, s);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f2b73dc..bfbcd57 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,10 +20,13 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.NetworkRegistrationState.Domain;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -56,7 +59,7 @@
* Normal operation condition, the phone is registered
* with an operator either in home network or in roaming.
*/
- public static final int STATE_IN_SERVICE = 0;
+ public static final int STATE_IN_SERVICE = TelephonyProtoEnums.SERVICE_STATE_IN_SERVICE; // 0
/**
* Phone is not registered with any operator, the phone
@@ -64,17 +67,19 @@
* searching to registration at all, or registration is denied, or radio
* signal is not available.
*/
- public static final int STATE_OUT_OF_SERVICE = 1;
+ public static final int STATE_OUT_OF_SERVICE =
+ TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE; // 1
/**
* The phone is registered and locked. Only emergency numbers are allowed. {@more}
*/
- public static final int STATE_EMERGENCY_ONLY = 2;
+ public static final int STATE_EMERGENCY_ONLY =
+ TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY; // 2
/**
* Radio of telephony is explicitly powered off.
*/
- public static final int STATE_POWER_OFF = 3;
+ public static final int STATE_POWER_OFF = TelephonyProtoEnums.SERVICE_STATE_POWER_OFF; // 3
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -197,6 +202,15 @@
private int mVoiceRegState = STATE_OUT_OF_SERVICE;
private int mDataRegState = STATE_OUT_OF_SERVICE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ROAMING_TYPE_" }, value = {
+ ROAMING_TYPE_NOT_ROAMING,
+ ROAMING_TYPE_UNKNOWN,
+ ROAMING_TYPE_DOMESTIC,
+ ROAMING_TYPE_INTERNATIONAL
+ })
+ public @interface RoamingType {}
/**
* Roaming type
* HOME : in home network
@@ -227,15 +241,13 @@
*/
public static final int UNKNOWN_ID = -1;
- private int mVoiceRoamingType;
- private int mDataRoamingType;
private String mVoiceOperatorAlphaLong;
private String mVoiceOperatorAlphaShort;
private String mVoiceOperatorNumeric;
private String mDataOperatorAlphaLong;
private String mDataOperatorAlphaShort;
private String mDataOperatorNumeric;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mIsManualNetworkSelection;
private boolean mIsEmergencyOnly;
@@ -245,9 +257,9 @@
@UnsupportedAppUsage
private boolean mCssIndicator;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mNetworkId;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mSystemId;
@UnsupportedAppUsage
private int mCdmaRoamingIndicator;
@@ -258,8 +270,6 @@
@UnsupportedAppUsage
private int mCdmaEriIconMode;
- private boolean mIsDataRoamingFromRegistration;
-
@UnsupportedAppUsage
private boolean mIsUsingCarrierAggregation;
@@ -331,8 +341,6 @@
protected void copyFrom(ServiceState s) {
mVoiceRegState = s.mVoiceRegState;
mDataRegState = s.mDataRegState;
- mVoiceRoamingType = s.mVoiceRoamingType;
- mDataRoamingType = s.mDataRoamingType;
mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
@@ -350,7 +358,6 @@
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
@@ -366,8 +373,6 @@
public ServiceState(Parcel in) {
mVoiceRegState = in.readInt();
mDataRegState = in.readInt();
- mVoiceRoamingType = in.readInt();
- mDataRoamingType = in.readInt();
mVoiceOperatorAlphaLong = in.readString();
mVoiceOperatorAlphaShort = in.readString();
mVoiceOperatorNumeric = in.readString();
@@ -385,7 +390,6 @@
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsDataRoamingFromRegistration = in.readInt() != 0;
mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationStates = new ArrayList<>();
@@ -397,8 +401,6 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mVoiceRegState);
out.writeInt(mDataRegState);
- out.writeInt(mVoiceRoamingType);
- out.writeInt(mDataRoamingType);
out.writeString(mVoiceOperatorAlphaLong);
out.writeString(mVoiceOperatorAlphaShort);
out.writeString(mVoiceOperatorNumeric);
@@ -416,7 +418,6 @@
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationStates);
@@ -456,7 +457,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getVoiceRegState() {
return mVoiceRegState;
}
@@ -471,7 +472,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getDataRegState() {
return mDataRegState;
}
@@ -532,19 +533,23 @@
* @return roaming status
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean getVoiceRoaming() {
- return mVoiceRoamingType != ROAMING_TYPE_NOT_ROAMING;
+ return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
-
/**
* Get current voice network roaming type
* @return roaming type
* @hide
*/
@UnsupportedAppUsage
- public int getVoiceRoamingType() {
- return mVoiceRoamingType;
+ public @RoamingType int getVoiceRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -552,21 +557,9 @@
* @return roaming type
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean getDataRoaming() {
- return mDataRoamingType != ROAMING_TYPE_NOT_ROAMING;
- }
-
- /**
- * Set whether data network registration state is roaming
- *
- * This should only be set to the roaming value received
- * once the data registration phase has completed.
- * @hide
- */
- @UnsupportedAppUsage
- public void setDataRoamingFromRegistration(boolean dataRoaming) {
- mIsDataRoamingFromRegistration = dataRoaming;
+ return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -575,7 +568,12 @@
* @hide
*/
public boolean getDataRoamingFromRegistration() {
- return mIsDataRoamingFromRegistration;
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+ }
+ return false;
}
/**
@@ -584,8 +582,13 @@
* @hide
*/
@UnsupportedAppUsage
- public int getDataRoamingType() {
- return mDataRoamingType;
+ public @RoamingType int getDataRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -758,8 +761,6 @@
return Objects.hash(
mVoiceRegState,
mDataRegState,
- mVoiceRoamingType,
- mDataRoamingType,
mChannelNumber,
mCellBandwidths,
mVoiceOperatorAlphaLong,
@@ -779,7 +780,6 @@
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsDataRoamingFromRegistration,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationStates);
@@ -793,8 +793,6 @@
return (mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
- && mVoiceRoamingType == s.mVoiceRoamingType
- && mDataRoamingType == s.mDataRoamingType
&& mChannelNumber == s.mChannelNumber
&& Arrays.equals(mCellBandwidths, s.mCellBandwidths)
&& equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
@@ -812,7 +810,6 @@
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
&& mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
s.mNetworkRegistrationStates != null &&
@@ -932,8 +929,6 @@
.append(", mChannelNumber=").append(mChannelNumber)
.append(", duplexMode()=").append(getDuplexMode())
.append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
- .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
- .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
.append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
.append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
.append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
@@ -950,7 +945,6 @@
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
.append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
@@ -961,8 +955,6 @@
if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
mVoiceRegState = state;
mDataRegState = state;
- mVoiceRoamingType = ROAMING_TYPE_NOT_ROAMING;
- mDataRoamingType = ROAMING_TYPE_NOT_ROAMING;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -982,7 +974,6 @@
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsDataRoamingFromRegistration = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
mNetworkRegistrationStates = new ArrayList<>();
@@ -1028,32 +1019,50 @@
}
public void setRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
- mDataRoamingType = mVoiceRoamingType;
+ setVoiceRoaming(roaming);
+ setDataRoaming(roaming);
}
/** @hide */
@UnsupportedAppUsage
public void setVoiceRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setVoiceRoamingType(roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setVoiceRoamingType(int type) {
- mVoiceRoamingType = type;
+ public void setVoiceRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/** @hide */
@UnsupportedAppUsage
public void setDataRoaming(boolean dataRoaming) {
- mDataRoamingType = (dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setDataRoamingType(dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setDataRoamingType(int type) {
- mDataRoamingType = type;
+ public void setDataRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/**
@@ -1165,30 +1174,10 @@
*/
@UnsupportedAppUsage
private void setFromNotifierBundle(Bundle m) {
- mVoiceRegState = m.getInt("voiceRegState");
- mDataRegState = m.getInt("dataRegState");
- mVoiceRoamingType = m.getInt("voiceRoamingType");
- mDataRoamingType = m.getInt("dataRoamingType");
- mVoiceOperatorAlphaLong = m.getString("operator-alpha-long");
- mVoiceOperatorAlphaShort = m.getString("operator-alpha-short");
- mVoiceOperatorNumeric = m.getString("operator-numeric");
- mDataOperatorAlphaLong = m.getString("data-operator-alpha-long");
- mDataOperatorAlphaShort = m.getString("data-operator-alpha-short");
- mDataOperatorNumeric = m.getString("data-operator-numeric");
- mIsManualNetworkSelection = m.getBoolean("manual");
- mRilVoiceRadioTechnology = m.getInt("radioTechnology");
- mRilDataRadioTechnology = m.getInt("dataRadioTechnology");
- mCssIndicator = m.getBoolean("cssIndicator");
- mNetworkId = m.getInt("networkId");
- mSystemId = m.getInt("systemId");
- mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
- mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
- mIsEmergencyOnly = m.getBoolean("emergencyOnly");
- mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
- mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
- mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
- mChannelNumber = m.getInt("ChannelNumber");
- mCellBandwidths = m.getIntArray("CellBandwidths");
+ ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE);
+ if (ssFromBundle != null) {
+ copyFrom(ssFromBundle);
+ }
}
/**
@@ -1199,10 +1188,13 @@
*/
@UnsupportedAppUsage
public void fillInNotifierBundle(Bundle m) {
+ m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
+ // serviceState already consists of below entries.
+ // for backward compatibility, we continue fill in below entries.
m.putInt("voiceRegState", mVoiceRegState);
m.putInt("dataRegState", mDataRegState);
- m.putInt("voiceRoamingType", mVoiceRoamingType);
- m.putInt("dataRoamingType", mDataRoamingType);
+ m.putInt("dataRoamingType", getDataRoamingType());
+ m.putInt("voiceRoamingType", getVoiceRoamingType());
m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
m.putString("operator-numeric", mVoiceOperatorNumeric);
@@ -1218,7 +1210,7 @@
m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
- m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+ m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
@@ -1595,7 +1587,7 @@
/**
* Get all of the available network registration states.
*
- * @return List of registration states
+ * @return List of {@link NetworkRegistrationState}
* @hide
*/
@SystemApi
@@ -1606,14 +1598,30 @@
}
/**
- * Get the network registration states with given transport type.
+ * Get the network registration states for the transport type.
*
- * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType}
- * @return List of registration states.
+ * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+ * @return List of {@link NetworkRegistrationState}
+ * @hide
+ *
+ * @deprecated Use {@link #getNetworkRegistrationStatesFromTransportType(int)}
+ */
+ @Deprecated
+ @SystemApi
+ public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
+ return getNetworkRegistrationStatesForTransportType(transportType);
+ }
+
+ /**
+ * Get the network registration states for the transport type.
+ *
+ * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+ * @return List of {@link NetworkRegistrationState}
* @hide
*/
@SystemApi
- public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
+ public List<NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(
+ int transportType) {
List<NetworkRegistrationState> list = new ArrayList<>();
synchronized (mNetworkRegistrationStates) {
@@ -1628,16 +1636,57 @@
}
/**
- * Get the network registration states with given transport type and domain.
+ * Get the network registration states for the network domain.
*
- * @param domain The network domain. Must be {@link NetworkRegistrationState#DOMAIN_CS} or
- * {@link NetworkRegistrationState#DOMAIN_PS}.
- * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType}
- * @return The matching NetworkRegistrationState.
+ * @param domain The network {@link NetworkRegistrationState.Domain domain}
+ * @return List of {@link NetworkRegistrationState}
* @hide
*/
@SystemApi
- public NetworkRegistrationState getNetworkRegistrationStates(int domain, int transportType) {
+ public List<NetworkRegistrationState> getNetworkRegistrationStatesForDomain(
+ @Domain int domain) {
+ List<NetworkRegistrationState> list = new ArrayList<>();
+
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getDomain() == domain) {
+ list.add(networkRegistrationState);
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * Get the network registration state for the transport type and network domain.
+ *
+ * @param domain The network {@link NetworkRegistrationState.Domain domain}
+ * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+ * @return The matching {@link NetworkRegistrationState}
+ * @hide
+ *
+ * @deprecated Use {@link #getNetworkRegistrationState(int, int)}
+ */
+ @Deprecated
+ @SystemApi
+ public NetworkRegistrationState getNetworkRegistrationStates(@Domain int domain,
+ int transportType) {
+ return getNetworkRegistrationState(domain, transportType);
+ }
+
+ /**
+ * Get the network registration state for the transport type and network domain.
+ *
+ * @param domain The network {@link NetworkRegistrationState.Domain domain}
+ * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+ * @return The matching {@link NetworkRegistrationState}
+ * @hide
+ *
+ */
+ @SystemApi
+ public NetworkRegistrationState getNetworkRegistrationState(@Domain int domain,
+ int transportType) {
synchronized (mNetworkRegistrationStates) {
for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
if (networkRegistrationState.getTransportType() == transportType
@@ -1669,5 +1718,4 @@
mNetworkRegistrationStates.add(regState);
}
}
-
}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ec26622..22c1e58 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -33,11 +33,13 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* A Parcelable class for Subscription Information.
@@ -552,11 +554,49 @@
String cardIdToPrint = givePrintableIccid(mCardId);
return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
- + " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " mNumber=" + mNumber
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
- + " mnc " + mMnc + " isEmbedded " + mIsEmbedded
+ + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
+ " accessRules " + Arrays.toString(mAccessRules)
+ " cardId=" + cardIdToPrint + " isOpportunistic " + mIsOpportunistic
+ " parentSubId=" + mParentSubId + "}";
}
-}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
+ mIsOpportunistic, mParentSubId, mIccId, mNumber, mMcc, mMnc, mCountryIso,
+ mCardId, mDisplayName, mCarrierName, mAccessRules);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ SubscriptionInfo toCompare;
+ try {
+ toCompare = (SubscriptionInfo) obj;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ return mId == toCompare.mId
+ && mSimSlotIndex == toCompare.mSimSlotIndex
+ && mNameSource == toCompare.mNameSource
+ && mIconTint == toCompare.mIconTint
+ && mDataRoaming == toCompare.mDataRoaming
+ && mIsEmbedded == toCompare.mIsEmbedded
+ && mIsOpportunistic == toCompare.mIsOpportunistic
+ && mParentSubId == toCompare.mParentSubId
+ && Objects.equals(mIccId, toCompare.mIccId)
+ && Objects.equals(mNumber, toCompare.mNumber)
+ && Objects.equals(mMcc, toCompare.mMcc)
+ && Objects.equals(mMnc, toCompare.mMnc)
+ && Objects.equals(mCountryIso, toCompare.mCountryIso)
+ && Objects.equals(mCardId, toCompare.mCardId)
+ && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
+ && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
+ && Arrays.equals(mAccessRules, toCompare.mAccessRules);
+ }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0c8280b..dfe35cd 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,15 +32,18 @@
import android.annotation.UnsupportedAppUsage;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.INetworkPolicyManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -59,6 +62,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -84,13 +88,10 @@
/** @hide */
public static final int INVALID_PHONE_INDEX = -1;
- /** An invalid slot identifier */
- /** @hide */
+ /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
public static final int INVALID_SIM_SLOT_INDEX = -1;
- /** Indicates the caller wants the default sub id. */
- /** @hide */
- @UnsupportedAppUsage
+ /** Indicates the default subscription ID in Telephony. */
public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
/**
@@ -116,6 +117,52 @@
@UnsupportedAppUsage
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * Generates a content {@link Uri} used to receive updates on simInfo change
+ * on the given subscriptionId
+ * @param subscriptionId the subscriptionId to receive updates on
+ * @return the Uri used to observe carrier identity changes
+ * @hide
+ */
+ public static Uri getUriForSubscriptionId(int subscriptionId) {
+ return Uri.withAppendedPath(CONTENT_URI, String.valueOf(subscriptionId));
+ }
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc enabled user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
+
+ /**
+ * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "enhanced_4g");
+
+
/**
* TelephonyProvider unique key column name is the subscription id.
* <P>Type: TEXT (String)</P>
@@ -1262,15 +1309,15 @@
/**
* Get slotIndex associated with the subscription.
- * @return slotIndex as a positive integer or a negative value if an error either
- * SIM_NOT_INSERTED or < 0 if an invalid slot index
- * @hide
+ *
+ * @param subscriptionId the unique SubscriptionInfo index in database
+ * @return slotIndex as a positive integer or {@link #INVALID_SIM_SLOT_INDEX} if the supplied
+ * subscriptionId doesn't have an associated slot index.
*/
- @UnsupportedAppUsage
- public static int getSlotIndex(int subId) {
- if (!isValidSubscriptionId(subId)) {
+ public static int getSlotIndex(int subscriptionId) {
+ if (!isValidSubscriptionId(subscriptionId)) {
if (DBG) {
- logd("[getSlotIndex]- fail");
+ logd("[getSlotIndex]- supplied subscriptionId is invalid.");
}
}
@@ -1279,7 +1326,7 @@
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getSlotIndex(subId);
+ result = iSub.getSlotIndex(subscriptionId);
}
} catch (RemoteException ex) {
// ignore it
@@ -1321,7 +1368,7 @@
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static int getPhoneId(int subId) {
if (!isValidSubscriptionId(subId)) {
if (DBG) {
@@ -1600,11 +1647,24 @@
}
/**
+ * Check if the subscription ID is usable.
+ *
+ * A usable subscription ID has a valid value except some special values such as
+ * {@link #DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
+ *
+ * @param subscriptionId the subscription ID
+ * @return {@code true} if the subscription ID is usable; {@code false} otherwise.
+ */
+ public static boolean isUsableSubscriptionId(int subscriptionId) {
+ return isUsableSubIdValue(subscriptionId);
+ }
+
+ /**
* @return true if subId is an usable subId value else false. A
* usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static boolean isUsableSubIdValue(int subId) {
return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
}
@@ -1622,7 +1682,7 @@
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
int[] subIds = SubscriptionManager.getSubId(phoneId);
if (subIds != null && subIds.length > 0) {
@@ -1810,6 +1870,19 @@
*/
@UnsupportedAppUsage
public static Resources getResourcesForSubId(Context context, int subId) {
+ return getResourcesForSubId(context, subId, false);
+ }
+
+ /**
+ * Returns the resources associated with Subscription.
+ * @param context Context object
+ * @param subId Subscription Id of Subscription who's resources are required
+ * @param useRootLocale if root locale should be used. Localized locale is used if false.
+ * @return Resources associated with Subscription.
+ * @hide
+ */
+ public static Resources getResourcesForSubId(Context context, int subId,
+ boolean useRootLocale) {
final SubscriptionInfo subInfo =
SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
@@ -1821,6 +1894,11 @@
newConfig.mnc = subInfo.getMnc();
if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO;
}
+
+ if (useRootLocale) {
+ newConfig.setLocale(Locale.ROOT);
+ }
+
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
DisplayMetrics newMetrics = new DisplayMetrics();
newMetrics.setTo(metrics);
@@ -1828,6 +1906,19 @@
}
/**
+ * Checks if the supplied subscription ID corresponds to an active subscription.
+ *
+ * @param subscriptionId the subscription ID.
+ * @return {@code true} if the supplied subscription ID corresponds to an active subscription;
+ * {@code false} if it does not correspond to an active subscription; or throw a
+ * SecurityException if the caller hasn't got the right permission.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isActiveSubscriptionId(int subscriptionId) {
+ return isActiveSubId(subscriptionId);
+ }
+
+ /**
* @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
* and the SIM providing the subscription is present in a slot and in "LOADED" state.
* @hide
@@ -1837,7 +1928,7 @@
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- return iSub.isActiveSubId(subId);
+ return iSub.isActiveSubId(subId, mContext.getOpPackageName());
}
} catch (RemoteException ex) {
}
@@ -2116,7 +2207,12 @@
/**
* Set preferred default data.
- * Set on which slot default data will be on.
+ * Set on which slot most cellular data will be on.
+ * It's also usually what we set up internet connection on.
+ *
+ * PreferredData overwrites user setting of default data subscription. And it's used
+ * by ANAS or carrier apps to switch primary and CBRS subscription dynamically in multi-SIM
+ * devices.
*
* @param slotId which slot is preferred to for cellular data.
* @hide
@@ -2130,20 +2226,21 @@
}
/**
- * Get User downloaded Profiles.
+ * Get opportunistic data Profiles.
*
- * Provide all available user downloaded profile on the phone.
- * @param slotId on which phone the switch will operate on
+ * Provide all available user downloaded profiles on phone which are used only for
+ * opportunistic data.
+ * @param slotIndex slot on which the profiles are queried from.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- List<SubscriptionInfo> getOpportunisticSubscriptions(int slotId) {
+ public List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
List<SubscriptionInfo> subInfoList = null;
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- subInfoList = iSub.getOpportunisticSubscriptions(slotId, pkgForDebug);
+ subInfoList = iSub.getOpportunisticSubscriptions(slotIndex, pkgForDebug);
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2cc175c..d3cf331 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static android.content.Context.TELECOM_SERVICE;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
@@ -39,6 +41,7 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.BatteryStats;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
@@ -58,15 +61,18 @@
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
+import com.android.internal.telephony.IAns;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyProperties;
@@ -163,7 +169,6 @@
/** @hide */
static public final int OTASP_SIM_UNPROVISIONED = 5;
-
/** @hide */
static public final int KEY_TYPE_EPDG = 1;
@@ -226,7 +231,8 @@
/** @hide
/* @deprecated - use getSystemService as described above */
- @UnsupportedAppUsage
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelephonyManager getDefault() {
return sInstance;
}
@@ -315,7 +321,7 @@
}
/** {@hide} */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelephonyManager from(Context context) {
return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
@@ -1498,23 +1504,24 @@
Rlog.d(TAG, "getCellLocation returning null because telephony is null");
return null;
}
+
Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
- if (bundle.isEmpty()) {
- Rlog.d(TAG, "getCellLocation returning null because bundle is empty");
+ if (bundle == null || bundle.isEmpty()) {
+ Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
return null;
}
+
CellLocation cl = CellLocation.newFromBundle(bundle);
- if (cl.isEmpty()) {
- Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty");
+ if (cl == null || cl.isEmpty()) {
+ Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
+ + " phone type doesn't match CellLocation type");
return null;
}
+
return cl;
} catch (RemoteException ex) {
Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex);
return null;
- } catch (NullPointerException ex) {
- Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex);
- return null;
}
}
@@ -1575,6 +1582,7 @@
*
* @return List of NeighboringCellInfo or null if info unavailable.
*
+ * @removed
* @deprecated Use {@link #getAllCellInfo} which returns a superset of the information
* from NeighboringCellInfo, including LTE cell information.
*/
@@ -1585,8 +1593,7 @@
ITelephony telephony = getITelephony();
if (telephony == null)
return null;
- return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
- mContext.getApplicationInfo().targetSdkVersion);
+ return telephony.getNeighboringCellInfo(mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1873,7 +1880,7 @@
* @param subId
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getNetworkOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1901,7 +1908,7 @@
* @param subId
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getNetworkOperator(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getNetworkOperatorForPhone(phoneId);
@@ -2087,10 +2094,37 @@
/** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_LTE_CA;
+
+ /** @hide */
+ @IntDef({
+ NETWORK_TYPE_UNKNOWN,
+ NETWORK_TYPE_GPRS,
+ NETWORK_TYPE_EDGE,
+ NETWORK_TYPE_UMTS,
+ NETWORK_TYPE_CDMA,
+ NETWORK_TYPE_EVDO_0,
+ NETWORK_TYPE_EVDO_A,
+ NETWORK_TYPE_1xRTT,
+ NETWORK_TYPE_HSDPA,
+ NETWORK_TYPE_HSUPA,
+ NETWORK_TYPE_HSPA,
+ NETWORK_TYPE_IDEN,
+ NETWORK_TYPE_EVDO_B,
+ NETWORK_TYPE_LTE,
+ NETWORK_TYPE_EHRPD,
+ NETWORK_TYPE_HSPAP,
+ NETWORK_TYPE_GSM,
+ NETWORK_TYPE_TD_SCDMA,
+ NETWORK_TYPE_IWLAN,
+ NETWORK_TYPE_LTE_CA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetworkType{}
+
/**
* @return the NETWORK_TYPE_xxxx for current data connection.
*/
- public int getNetworkType() {
+ public @NetworkType int getNetworkType() {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
@@ -2135,24 +2169,24 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
- public int getNetworkType(int subId) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
- } else {
- // This can happen when the ITelephony interface is not up yet.
- return NETWORK_TYPE_UNKNOWN;
- }
- } catch(RemoteException ex) {
- // This shouldn't happen in the normal case
- return NETWORK_TYPE_UNKNOWN;
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing
- return NETWORK_TYPE_UNKNOWN;
- }
- }
+ @UnsupportedAppUsage
+ public int getNetworkType(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ } catch (RemoteException ex) {
+ // This shouldn't happen in the normal case
+ return NETWORK_TYPE_UNKNOWN;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ }
/**
* Returns a constant indicating the radio technology (network type)
@@ -2185,7 +2219,7 @@
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getDataNetworkType() {
+ public @NetworkType int getDataNetworkType() {
return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
@@ -2198,7 +2232,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getDataNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -2225,7 +2259,7 @@
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getVoiceNetworkType() {
+ public @NetworkType int getVoiceNetworkType() {
return getVoiceNetworkType(getSubId());
}
@@ -2234,7 +2268,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getVoiceNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -2387,39 +2421,46 @@
*
* These are the ordinal value of IccCardConstants.State.
*/
- public static final int SIM_STATE_UNKNOWN = 0;
+
+ public static final int SIM_STATE_UNKNOWN = TelephonyProtoEnums.SIM_STATE_UNKNOWN; // 0
/** SIM card state: no SIM card is available in the device */
- public static final int SIM_STATE_ABSENT = 1;
+ public static final int SIM_STATE_ABSENT = TelephonyProtoEnums.SIM_STATE_ABSENT; // 1
/** SIM card state: Locked: requires the user's SIM PIN to unlock */
- public static final int SIM_STATE_PIN_REQUIRED = 2;
+ public static final int SIM_STATE_PIN_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PIN_REQUIRED; // 2
/** SIM card state: Locked: requires the user's SIM PUK to unlock */
- public static final int SIM_STATE_PUK_REQUIRED = 3;
+ public static final int SIM_STATE_PUK_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PUK_REQUIRED; // 3
/** SIM card state: Locked: requires a network PIN to unlock */
- public static final int SIM_STATE_NETWORK_LOCKED = 4;
+ public static final int SIM_STATE_NETWORK_LOCKED =
+ TelephonyProtoEnums.SIM_STATE_NETWORK_LOCKED; // 4
/** SIM card state: Ready */
- public static final int SIM_STATE_READY = 5;
+ public static final int SIM_STATE_READY = TelephonyProtoEnums.SIM_STATE_READY; // 5
/** SIM card state: SIM Card is NOT READY */
- public static final int SIM_STATE_NOT_READY = 6;
+ public static final int SIM_STATE_NOT_READY = TelephonyProtoEnums.SIM_STATE_NOT_READY; // 6
/** SIM card state: SIM Card Error, permanently disabled */
- public static final int SIM_STATE_PERM_DISABLED = 7;
+ public static final int SIM_STATE_PERM_DISABLED =
+ TelephonyProtoEnums.SIM_STATE_PERM_DISABLED; // 7
/** SIM card state: SIM Card Error, present but faulty */
- public static final int SIM_STATE_CARD_IO_ERROR = 8;
+ public static final int SIM_STATE_CARD_IO_ERROR =
+ TelephonyProtoEnums.SIM_STATE_CARD_IO_ERROR; // 8
/** SIM card state: SIM Card restricted, present but not usable due to
* carrier restrictions.
*/
- public static final int SIM_STATE_CARD_RESTRICTED = 9;
+ public static final int SIM_STATE_CARD_RESTRICTED =
+ TelephonyProtoEnums.SIM_STATE_CARD_RESTRICTED; // 9
/**
* SIM card state: Loaded: SIM card applications have been loaded
* @hide
*/
@SystemApi
- public static final int SIM_STATE_LOADED = 10;
+ public static final int SIM_STATE_LOADED = TelephonyProtoEnums.SIM_STATE_LOADED; // 10
/**
* SIM card state: SIM Card is present
* @hide
*/
@SystemApi
- public static final int SIM_STATE_PRESENT = 11;
+ public static final int SIM_STATE_PRESENT = TelephonyProtoEnums.SIM_STATE_PRESENT; // 11
/**
* Extra included in {@link #ACTION_SIM_CARD_STATE_CHANGED} and
@@ -2710,7 +2751,7 @@
* @param subId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperator(int subId) {
return getSimOperatorNumeric(subId);
}
@@ -2724,7 +2765,7 @@
* @see #getSimState
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumeric() {
int subId = mSubId;
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
@@ -2753,7 +2794,7 @@
* @param subId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumeric(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNumericForPhone(phoneId);
@@ -2767,7 +2808,7 @@
* @param phoneId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumericForPhone(int phoneId) {
return getTelephonyProperty(phoneId,
TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
@@ -2794,7 +2835,7 @@
* @param subId for which SimOperatorName is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNameForPhone(phoneId);
@@ -2824,7 +2865,7 @@
* @param subId for which SimCountryIso is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimCountryIso(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimCountryIsoForPhone(phoneId);
@@ -2882,7 +2923,7 @@
* of time the mode may be unknown.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
* or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
@@ -3014,7 +3055,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSubscriberId(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -3399,7 +3440,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getMsisdn(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -4137,11 +4178,16 @@
}
/**
- * Returns the IMS home network domain name that was loaded from the ISIM.
- * @return the IMS domain name, or null if not present or not loaded
+ * Returns the IMS home network domain name that was loaded from the ISIM {@see #APPTYPE_ISIM}.
+ * @return the IMS domain name. Returns {@code null} if ISIM hasn't been loaded or IMS domain
+ * hasn't been loaded or isn't present on the ISIM.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getIsimDomain() {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -4360,7 +4406,7 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
@@ -4369,13 +4415,17 @@
* @hide
*/
private ITelecomService getTelecomService() {
- return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
+ return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
}
private ITelephonyRegistry getTelephonyRegistry() {
return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
}
+ private IAns getIAns() {
+ return IAns.Stub.asInterface(ServiceManager.getService("ians"));
+ }
+
//
//
// PhoneStateListener
@@ -5338,7 +5388,7 @@
@UnsupportedAppUsage
public static String getTelephonyProperty(String property, String defaultVal) {
String propVal = SystemProperties.get(property);
- return propVal == null ? defaultVal : propVal;
+ return TextUtils.isEmpty(propVal) ? defaultVal : propVal;
}
/** @hide */
@@ -5395,7 +5445,19 @@
}
}
- // ICC SIM Application Types
+ /**
+ * UICC SIM Application Types
+ * @hide
+ */
+ @IntDef(prefix = { "APPTYPE_" }, value = {
+ APPTYPE_SIM,
+ APPTYPE_USIM,
+ APPTYPE_RUIM,
+ APPTYPE_CSIM,
+ APPTYPE_ISIM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UiccAppType{}
/** UICC application type is SIM */
public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
/** UICC application type is USIM */
@@ -5406,6 +5468,7 @@
public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
/** UICC application type is ISIM */
public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+
// authContext (parameter P2) when doing UICC challenge,
// per 3GPP TS 31.102 (Section 7.1.2)
/** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */
@@ -5657,23 +5720,6 @@
}
/**
- * @return true if the IMS resolver is busy resolving a binding and should not be considered
- * available, false if the IMS resolver is idle.
- * @hide
- */
- public boolean isResolvingImsBinding() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- return telephony.isResolvingImsBinding();
- }
- } catch (RemoteException e) {
- Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage());
- }
- return false;
- }
-
- /**
* Set IMS registration state
*
* @param Registration state
@@ -5689,6 +5735,203 @@
}
}
+ /** @hide */
+ @IntDef(prefix = { "NETWORK_MODE_" }, value = {
+ NETWORK_MODE_WCDMA_PREF,
+ NETWORK_MODE_GSM_ONLY,
+ NETWORK_MODE_WCDMA_ONLY,
+ NETWORK_MODE_GSM_UMTS,
+ NETWORK_MODE_CDMA_EVDO,
+ NETWORK_MODE_CDMA_NO_EVDO,
+ NETWORK_MODE_EVDO_NO_CDMA,
+ NETWORK_MODE_GLOBAL,
+ NETWORK_MODE_LTE_CDMA_EVDO,
+ NETWORK_MODE_LTE_GSM_WCDMA,
+ NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_LTE_ONLY,
+ NETWORK_MODE_LTE_WCDMA,
+ NETWORK_MODE_TDSCDMA_ONLY,
+ NETWORK_MODE_TDSCDMA_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA,
+ NETWORK_MODE_TDSCDMA_GSM,
+ NETWORK_MODE_LTE_TDSCDMA_GSM,
+ NETWORK_MODE_TDSCDMA_GSM_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA,
+ NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PrefNetworkMode{}
+
+ /**
+ * network mode is GSM/WCDMA (WCDMA preferred).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF;
+
+ /**
+ * network mode is GSM only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY;
+
+ /**
+ * network mode is WCDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY;
+
+ /**
+ * network mode is GSM/WCDMA (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS;
+
+ /**
+ * network mode is CDMA and EvDo (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA;
+
+ /**
+ * network mode is CDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
+
+ /**
+ * network mode is EvDo only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
+
+ /**
+ * network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL).
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL;
+
+ /**
+ * network mode is LTE, CDMA and EvDo.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
+
+ /**
+ * preferred network mode is LTE, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
+
+ /**
+ * network mode is LTE, CDMA, EvDo, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
+
+ /**
+ * network mode is LTE Only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY;
+
+ /**
+ * network mode is LTE/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA only.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
+
+ /**
+ * network mode is TD-SCDMA and WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
+
+ /**
+ * network mode is TD-SCDMA and GSM.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
+
+ /**
+ * network mode is TD-SCDMA,GSM and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_GSM =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
+
+ /**
+ * network mode is TD-SCDMA, GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA, WCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA, GSM/WCDMA and LTE.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+
+ /**
+ * network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo.
+ * @hide
+ */
+ @SystemApi
+ public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+
/**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
@@ -5697,11 +5940,12 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * @return the preferred network type, defined in RILConstants.java.
+ * @return the preferred network type.
* @hide
*/
- @UnsupportedAppUsage
- public int getPreferredNetworkType(int subId) {
+ @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+ @SystemApi
+ public @PrefNetworkMode int getPreferredNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
@@ -5718,7 +5962,7 @@
* Sets the network selection mode to automatic.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
@@ -5743,7 +5987,7 @@
* Perform a radio scan and return the list of available networks.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* <p> Note that this scan can take a long time (sometimes minutes) to happen.
*
@@ -5822,7 +6066,7 @@
* Ask the radio to connect to the input network and change selection mode to manual.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
@@ -5832,21 +6076,46 @@
* @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true on success; false on any failure.
+ * @return {@code true} on success; {@code false} on any failure.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
+ return setNetworkSelectionModeManual(
+ new OperatorInfo(
+ "" /* operatorAlphaLong */, "" /* operatorAlphaShort */, operatorNumeric),
+ persistSelection);
+ }
+
+ /**
+ * Ask the radio to connect to the input network and change selection mode to manual.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param operatorInfo included the PLMN id, long name, short name of the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
+ * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+ * normal network selection next time.
+ * @return {@code true} on success; {@code true} on any failure.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setNetworkSelectionModeManual(
+ OperatorInfo operatorInfo, boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.setNetworkSelectionModeManual(
- getSubId(), operatorNumeric, persistSelection);
+ getSubId(), operatorInfo, persistSelection);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "setNetworkSelectionModeManual NPE", ex);
}
return false;
}
@@ -5855,7 +6124,7 @@
* Get the network selection mode.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
* @return the network selection mode.
*
@@ -6258,57 +6527,42 @@
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#endCall()} instead.
+ * @removed Use {@link android.telecom.TelecomManager#endCall()} instead.
* @hide
+ * @removed
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public boolean endCall() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.endCall();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#endCall", e);
- }
return false;
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
* @hide
+ * @removed
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void answerRingingCall() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.answerRingingCall();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
- }
+ // No-op
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#silenceRinger} instead
+ * @removed Use {@link android.telecom.TelecomManager#silenceRinger} instead
* @hide
*/
@Deprecated
@SystemApi
@SuppressLint("Doclava125")
public void silenceRinger() {
- try {
- getTelecomService().silenceRinger(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
- }
+ // No-op
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
* @hide
*/
@Deprecated
@@ -6318,18 +6572,11 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isOffhook() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isOffhook(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isOffhook", e);
- }
return false;
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead
+ * @removed Use {@link android.telecom.TelecomManager#isRinging} instead
* @hide
*/
@Deprecated
@@ -6339,18 +6586,11 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isRinging() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isRinging(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isRinging", e);
- }
return false;
}
/**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+ * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
* @hide
*/
@Deprecated
@@ -6360,13 +6600,6 @@
android.Manifest.permission.READ_PHONE_STATE
})
public boolean isIdle() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.isIdle(getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isIdle", e);
- }
return true;
}
@@ -6623,6 +6856,60 @@
}
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"RADIO_POWER_"},
+ value = {RADIO_POWER_OFF,
+ RADIO_POWER_ON,
+ RADIO_POWER_UNAVAILABLE,
+ })
+ public @interface RadioPowerState {}
+
+ /**
+ * Radio explicitly powered off (e.g, airplane mode).
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_OFF = 0;
+
+ /**
+ * Radio power is on.
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_ON = 1;
+
+ /**
+ * Radio power unavailable (eg, modem resetting or not booted).
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_UNAVAILABLE = 2;
+
+ /**
+ * @return current modem radio state.
+ *
+ * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+ * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE})
+ public @RadioPowerState int getRadioPowerState() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return RADIO_POWER_UNAVAILABLE;
+ }
+
+ /** @hide */
@SystemApi
@SuppressLint("Doclava125")
public void updateServiceLocation() {
@@ -6781,7 +7068,8 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- isDataRoamingEnabled = telephony.isDataRoamingEnabled(getSubId());
+ isDataRoamingEnabled = telephony.isDataRoamingEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#isDataRoamingEnabled", e);
@@ -6793,7 +7081,7 @@
* Gets the roaming mode for CDMA phone.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* @return one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, {@link #CDMA_ROAMING_MODE_HOME},
* {@link #CDMA_ROAMING_MODE_AFFILIATED}, {@link #CDMA_ROAMING_MODE_ANY}.
@@ -6818,7 +7106,7 @@
* Sets the roaming mode for CDMA phone to the given mode {@code mode}.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* @param mode should be one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT},
* {@link #CDMA_ROAMING_MODE_HOME}, {@link #CDMA_ROAMING_MODE_AFFILIATED},
@@ -6887,7 +7175,8 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- telephony.setDataRoamingEnabled(getSubId(), isEnabled);
+ telephony.setDataRoamingEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), isEnabled);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#setDataRoamingEnabled", e);
@@ -7680,7 +7969,7 @@
* Returns the current {@link ServiceState} information.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -7696,7 +7985,7 @@
* either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public ServiceState getServiceStateForSubscriber(int subId) {
try {
ITelephony service = getITelephony();
@@ -7852,26 +8141,23 @@
}
/**
- * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+ * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
+ * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
*
- * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
- *
- * @param appType the uicc app type like {@link APPTYPE_CSIM}
- * @return Application ID for specificied app type or null if no uicc or error.
+ * @param appType the uicc app type.
+ * @return Application ID for specified app type or {@code null} if no uicc or error.
* @hide
*/
- public String getAidForAppType(int appType) {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public String getAidForAppType(@UiccAppType int appType) {
return getAidForAppType(getSubId(), appType);
}
/**
- * Return the application ID for the app type like {@link APPTYPE_CSIM}.
- *
- * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
- *
- * @param subId the subscription ID that this request applies to.
- * @param appType the uicc app type, like {@link APPTYPE_CSIM}
- * @return Application ID for specificied app type or null if no uicc or error.
+ * same as {@link #getAidForAppType(int)}
* @hide
*/
public String getAidForAppType(int subId, int appType) {
@@ -8152,7 +8438,7 @@
* Checks if phone is in emergency callback mode.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
- * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* @return true if phone is in emergency callback mode.
* @hide
@@ -8183,6 +8469,29 @@
}
/**
+ * Checks if manual network selection is allowed.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @return {@code true} if manual network selection is allowed, otherwise return {@code false}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isManualNetworkSelectionAllowed() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isManualNetworkSelectionAllowed(getSubId());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#isManualNetworkSelectionAllowed", e);
+ }
+ return true;
+ }
+
+ /**
* Get the most recently available signal strength information.
*
* Get the most recent SignalStrength information reported by the modem. Due
@@ -8362,7 +8671,6 @@
return UNKNOWN_CARRIER_ID_LIST_VERSION;
}
-
/**
* How many modems can have simultaneous data connections.
* @hide
@@ -8380,4 +8688,62 @@
}
return 0;
}
+
+ /**
+ * Enable or disable AlternativeNetworkService.
+ *
+ * This method should be called to enable or disable
+ * AlternativeNetwork service on the device.
+ *
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @param enable enable(True) or disable(False)
+ * @return returns true if successfully set.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setAlternativeNetworkState(boolean enable) {
+ String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ boolean ret = false;
+ try {
+ IAns iAlternativeNetworkService = getIAns();
+ if (iAlternativeNetworkService != null) {
+ ret = iAlternativeNetworkService.setEnable(enable, pkgForDebug);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+ }
+
+ return ret;
+ }
+
+ /**
+ * is AlternativeNetworkService enabled
+ *
+ * This method should be called to determine if the AlternativeNetworkService is
+ * enabled
+ *
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isAlternativeNetworkEnabled() {
+ String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ boolean isEnabled = false;
+
+ try {
+ IAns iAlternativeNetworkService = getIAns();
+ if (iAlternativeNetworkService != null) {
+ isEnabled = iAlternativeNetworkService.isEnabled(pkgForDebug);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+ }
+
+ return isEnabled;
+ }
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 0e4a7ad..ed14f91 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -31,6 +31,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
@@ -256,7 +257,7 @@
private final int mProfileId;
- private final boolean mModemCognitive;
+ private final boolean mPersistent;
private final int mMaxConns;
private final int mWaitTime;
private final int mMaxConnsTime;
@@ -289,13 +290,13 @@
}
/**
- * Returns if the APN setting is to be set in modem.
+ * Returns if the APN setting is persistent on the modem.
*
* @return is the APN setting to be set in modem
* @hide
*/
- public boolean getModemCognitive() {
- return mModemCognitive;
+ public boolean isPersistent() {
+ return mPersistent;
}
/**
@@ -615,7 +616,7 @@
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
- this.mModemCognitive = builder.mModemCognitive;
+ this.mPersistent = builder.mModemCognitive;
this.mMaxConns = builder.mMaxConns;
this.mWaitTime = builder.mWaitTime;
this.mMaxConnsTime = builder.mMaxConnsTime;
@@ -633,33 +634,33 @@
int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
String mvnoMatchData, int apnSetId) {
return new Builder()
- .setId(id)
- .setOperatorNumeric(operatorNumeric)
- .setEntryName(entryName)
- .setApnName(apnName)
- .setProxyAddress(proxyAddress)
- .setProxyPort(proxyPort)
- .setMmsc(mmsc)
- .setMmsProxyAddress(mmsProxyAddress)
- .setMmsProxyPort(mmsProxyPort)
- .setUser(user)
- .setPassword(password)
- .setAuthType(authType)
- .setApnTypeBitmask(mApnTypeBitmask)
- .setProtocol(protocol)
- .setRoamingProtocol(roamingProtocol)
- .setCarrierEnabled(carrierEnabled)
- .setNetworkTypeBitmask(networkTypeBitmask)
- .setProfileId(profileId)
- .setModemCognitive(modemCognitive)
- .setMaxConns(maxConns)
- .setWaitTime(waitTime)
- .setMaxConnsTime(maxConnsTime)
- .setMtu(mtu)
- .setMvnoType(mvnoType)
- .setMvnoMatchData(mvnoMatchData)
- .setApnSetId(apnSetId)
- .buildWithoutCheck();
+ .setId(id)
+ .setOperatorNumeric(operatorNumeric)
+ .setEntryName(entryName)
+ .setApnName(apnName)
+ .setProxyAddress(proxyAddress)
+ .setProxyPort(proxyPort)
+ .setMmsc(mmsc)
+ .setMmsProxyAddress(mmsProxyAddress)
+ .setMmsProxyPort(mmsProxyPort)
+ .setUser(user)
+ .setPassword(password)
+ .setAuthType(authType)
+ .setApnTypeBitmask(mApnTypeBitmask)
+ .setProtocol(protocol)
+ .setRoamingProtocol(roamingProtocol)
+ .setCarrierEnabled(carrierEnabled)
+ .setNetworkTypeBitmask(networkTypeBitmask)
+ .setProfileId(profileId)
+ .setModemCognitive(modemCognitive)
+ .setMaxConns(maxConns)
+ .setWaitTime(waitTime)
+ .setMaxConnsTime(maxConnsTime)
+ .setMtu(mtu)
+ .setMvnoType(mvnoType)
+ .setMvnoMatchData(mvnoMatchData)
+ .setApnSetId(apnSetId)
+ .buildWithoutCheck();
}
/** @hide */
@@ -691,56 +692,56 @@
}
return makeApnSetting(
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
- UriFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
- apnTypesBitmask,
- getProtocolIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
- getProtocolIntFromString(
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+ portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
+ UriFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+ portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
+ apnTypesBitmask,
+ getProtocolIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
+ getProtocolIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.ROAMING_PROTOCOL))),
+ cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.CARRIER_ENABLED)) == 1,
+ networkTypeBitmask,
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MODEM_COGNITIVE)) == 1,
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MAX_CONNS_TIME)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
+ getMvnoTypeIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_TYPE))),
cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.ROAMING_PROTOCOL))),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.CARRIER_ENABLED)) == 1,
- networkTypeBitmask,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MODEM_COGNITIVE)) == 1,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MAX_CONNS_TIME)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
- getMvnoTypeIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_TYPE))),
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_MATCH_DATA)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
+ Telephony.Carriers.MVNO_MATCH_DATA)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
}
/** @hide */
public static ApnSetting makeApnSetting(ApnSetting apn) {
return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
- apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
- apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
- apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
- apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
- apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
+ apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
+ apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
+ apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
+ apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime,
+ apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
}
/**
@@ -930,23 +931,23 @@
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ApnSettingV5] ")
- .append(mEntryName)
- .append(", ").append(mId)
- .append(", ").append(mOperatorNumeric)
- .append(", ").append(mApnName)
- .append(", ").append(mProxyAddress)
- .append(", ").append(UriToString(mMmsc))
- .append(", ").append(mMmsProxyAddress)
- .append(", ").append(portToString(mMmsProxyPort))
- .append(", ").append(portToString(mProxyPort))
- .append(", ").append(mAuthType).append(", ");
+ .append(mEntryName)
+ .append(", ").append(mId)
+ .append(", ").append(mOperatorNumeric)
+ .append(", ").append(mApnName)
+ .append(", ").append(mProxyAddress)
+ .append(", ").append(UriToString(mMmsc))
+ .append(", ").append(mMmsProxyAddress)
+ .append(", ").append(portToString(mMmsProxyPort))
+ .append(", ").append(portToString(mProxyPort))
+ .append(", ").append(mAuthType).append(", ");
final String[] types = getApnTypesStringFromBitmask(mApnTypeBitmask).split(",");
sb.append(TextUtils.join(" | ", types));
sb.append(", ").append(PROTOCOL_INT_MAP.get(mProtocol));
sb.append(", ").append(PROTOCOL_INT_MAP.get(mRoamingProtocol));
sb.append(", ").append(mCarrierEnabled);
sb.append(", ").append(mProfileId);
- sb.append(", ").append(mModemCognitive);
+ sb.append(", ").append(mPersistent);
sb.append(", ").append(mMaxConns);
sb.append(", ").append(mWaitTime);
sb.append(", ").append(mMaxConnsTime);
@@ -1021,31 +1022,31 @@
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mId, other.mId)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && Objects.equals(mProtocol, other.mProtocol)
- && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
- && Objects.equals(mApnSetId, other.mApnSetId);
+ && Objects.equals(mId, other.mId)
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && Objects.equals(mProtocol, other.mProtocol)
+ && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtu, other.mMtu)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+ && Objects.equals(mApnSetId, other.mApnSetId);
}
/**
@@ -1068,29 +1069,29 @@
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
- && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mApnSetId, other.mApnSetId);
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
+ && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtu, other.mMtu)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mApnSetId, other.mApnSetId);
}
/**
@@ -1102,22 +1103,22 @@
*/
public boolean similar(ApnSetting other) {
return (!this.canHandleType(TYPE_DUN)
- && !other.canHandleType(TYPE_DUN)
- && Objects.equals(this.mApnName, other.mApnName)
- && !typeSameAny(this, other)
- && xorEquals(this.mProxyAddress, other.mProxyAddress)
- && xorEqualsInt(this.mProxyPort, other.mProxyPort)
- && xorEquals(this.mProtocol, other.mProtocol)
- && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
- && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(this.mProfileId, other.mProfileId)
- && Objects.equals(this.mMvnoType, other.mMvnoType)
- && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
- && xorEquals(this.mMmsc, other.mMmsc)
- && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
- && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
- && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
- && Objects.equals(mApnSetId, other.mApnSetId);
+ && !other.canHandleType(TYPE_DUN)
+ && Objects.equals(this.mApnName, other.mApnName)
+ && !typeSameAny(this, other)
+ && xorEquals(this.mProxyAddress, other.mProxyAddress)
+ && xorEqualsInt(this.mProxyPort, other.mProxyPort)
+ && xorEquals(this.mProtocol, other.mProtocol)
+ && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
+ && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(this.mProfileId, other.mProfileId)
+ && Objects.equals(this.mMvnoType, other.mMvnoType)
+ && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
+ && xorEquals(this.mMmsc, other.mMmsc)
+ && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+ && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
+ && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+ && Objects.equals(mApnSetId, other.mApnSetId);
}
// Equal or one is null.
@@ -1205,7 +1206,8 @@
/** @hide */
public static int getMvnoTypeIntFromString(String mvnoType) {
- Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoType);
+ String mvnoTypeString = TextUtils.isEmpty(mvnoType) ? mvnoType : mvnoType.toLowerCase();
+ Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString);
return mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt;
}
@@ -1341,13 +1343,13 @@
new Parcelable.Creator<ApnSetting>() {
@Override
public ApnSetting createFromParcel(Parcel in) {
- return readFromParcel(in);
- }
+ return readFromParcel(in);
+ }
@Override
public ApnSetting[] newArray(int size) {
- return new ApnSetting[size];
- }
+ return new ApnSetting[size];
+ }
};
/**
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index e8597b2..da4822c 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -68,17 +68,15 @@
private final int mMtu;
- private final String mMvnoType;
+ private final boolean mPersistent;
- private final String mMvnoMatchData;
+ private final boolean mPreferred;
- private final boolean mModemCognitive;
-
- public DataProfile(int profileId, String apn, String protocol, int authType,
- String userName, String password, int type, int maxConnsTime, int maxConns,
- int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
- int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
- boolean modemCognitive) {
+ /** @hide */
+ public DataProfile(int profileId, String apn, String protocol, int authType, String userName,
+ String password, int type, int maxConnsTime, int maxConns, int waitTime,
+ boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+ int bearerBitmap, int mtu, boolean persistent, boolean preferred) {
this.mProfileId = profileId;
this.mApn = apn;
@@ -100,11 +98,11 @@
this.mRoamingProtocol = roamingProtocol;
this.mBearerBitmap = bearerBitmap;
this.mMtu = mtu;
- this.mMvnoType = mvnoType;
- this.mMvnoMatchData = mvnoMatchData;
- this.mModemCognitive = modemCognitive;
+ this.mPersistent = persistent;
+ this.mPreferred = preferred;
}
+ /** @hide */
public DataProfile(Parcel source) {
mProfileId = source.readInt();
mApn = source.readString();
@@ -121,9 +119,8 @@
mRoamingProtocol = source.readString();
mBearerBitmap = source.readInt();
mMtu = source.readInt();
- mMvnoType = source.readString();
- mMvnoMatchData = source.readString();
- mModemCognitive = source.readBoolean();
+ mPersistent = source.readBoolean();
+ mPreferred = source.readBoolean();
}
/**
@@ -207,23 +204,17 @@
public int getMtu() { return mMtu; }
/**
- * @return The MVNO type: possible values are "imsi", "gid", "spn".
+ * @return {@code true} if modem must persist this data profile.
*/
- public String getMvnoType() { return mMvnoType; }
+ public boolean isPersistent() { return mPersistent; }
/**
- * @return The MVNO match data. For example,
- * SPN: A MOBILE, BEN NL, ...
- * IMSI: 302720x94, 2060188, ...
- * GID: 4E, 33, ...
+ * @return {@code true} if this data profile was used to bring up the last default
+ * (i.e internet) data connection successfully.
*/
- public String getMvnoMatchData() { return mMvnoMatchData; }
+ public boolean isPreferred() { return mPreferred; }
- /**
- * @return True if the data profile was sent to the modem through setDataProfile earlier.
- */
- public boolean isModemCognitive() { return mModemCognitive; }
-
+ /** @hide */
@Override
public int describeContents() {
return 0;
@@ -233,11 +224,11 @@
public String toString() {
return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+ "/" + (Build.IS_USER ? "***/***/***" :
- (mApn + "/" + mUserName + "/" + mPassword))
- + "/" + mType + "/" + mMaxConnsTime
- + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
- + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
- + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+ (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
+ + mMaxConnsTime + "/" + mMaxConns + "/"
+ + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/"
+ + mRoamingProtocol + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
+ + mPreferred;
}
@Override
@@ -246,6 +237,7 @@
return (o == this || toString().equals(o.toString()));
}
+ /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mProfileId);
@@ -263,11 +255,11 @@
dest.writeString(mRoamingProtocol);
dest.writeInt(mBearerBitmap);
dest.writeInt(mMtu);
- dest.writeString(mMvnoType);
- dest.writeString(mMvnoMatchData);
- dest.writeBoolean(mModemCognitive);
+ dest.writeBoolean(mPersistent);
+ dest.writeBoolean(mPreferred);
}
+ /** @hide */
public static final Parcelable.Creator<DataProfile> CREATOR =
new Parcelable.Creator<DataProfile>() {
@Override
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.aidl b/telephony/java/android/telephony/emergency/EmergencyNumber.aidl
new file mode 100644
index 0000000..bfb0a59
--- /dev/null
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telephony.emergency;
+
+parcelable EmergencyNumber;
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
new file mode 100644
index 0000000..bdba8c8
--- /dev/null
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -0,0 +1,434 @@
+/*
+ * 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.telephony.emergency;
+
+import android.annotation.IntDef;
+import android.hardware.radio.V1_3.EmergencyNumberSource;
+import android.hardware.radio.V1_3.EmergencyServiceCategory;
+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.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A parcelable class that wraps and retrieves the information of number, service category(s) and
+ * country code for a specific emergency number.
+ */
+public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNumber> {
+
+ private static final String LOG_TAG = "EmergencyNumber";
+
+ /**
+ * Defining Emergency Service Category as follows:
+ * - General emergency call, all categories;
+ * - Police;
+ * - Ambulance;
+ * - Fire Brigade;
+ * - Marine Guard;
+ * - Mountain Rescue;
+ * - Manually Initiated eCall (MIeC);
+ * - Automatically Initiated eCall (AIeC);
+ *
+ * Category UNSPECIFIED (General emergency call, all categories) indicates that no specific
+ * services are associated with this emergency number; if the emergency number is specified,
+ * it has one or more defined emergency service categories.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "EMERGENCY_SERVICE_CATEGORY_" }, value = {
+ EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ EMERGENCY_SERVICE_CATEGORY_POLICE,
+ EMERGENCY_SERVICE_CATEGORY_AMBULANCE,
+ EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+ EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD,
+ EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE,
+ EMERGENCY_SERVICE_CATEGORY_MIEC,
+ EMERGENCY_SERVICE_CATEGORY_AIEC
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EmergencyServiceCategories {}
+
+ /**
+ * Emergency Service Category UNSPECIFIED (General emergency call, all categories) bit-field
+ * indicates that no specific services are associated with this emergency number; if the
+ * emergency number is specified, it has one or more defined emergency service categories.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED =
+ EmergencyServiceCategory.UNSPECIFIED;
+ /**
+ * Bit-field that indicates Emergency Service Category for Police.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_POLICE = EmergencyServiceCategory.POLICE;
+ /**
+ * Bit-field that indicates Emergency Service Category for Ambulance.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_AMBULANCE =
+ EmergencyServiceCategory.AMBULANCE;
+ /**
+ * Bit-field that indicates Emergency Service Category for Fire Brigade.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE =
+ EmergencyServiceCategory.FIRE_BRIGADE;
+ /**
+ * Bit-field that indicates Emergency Service Category for Marine Guard.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD =
+ EmergencyServiceCategory.MARINE_GUARD;
+ /**
+ * Bit-field that indicates Emergency Service Category for Mountain Rescue.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE =
+ EmergencyServiceCategory.MOUNTAIN_RESCUE;
+ /**
+ * Bit-field that indicates Emergency Service Category for Manually Initiated eCall (MIeC)
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_MIEC = EmergencyServiceCategory.MIEC;
+ /**
+ * Bit-field that indicates Emergency Service Category for Automatically Initiated eCall (AIeC)
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_SERVICE_CATEGORY_AIEC = EmergencyServiceCategory.AIEC;
+
+ private static final Set<Integer> EMERGENCY_SERVICE_CATEGORY_SET;
+ static {
+ EMERGENCY_SERVICE_CATEGORY_SET = new HashSet<Integer>();
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_POLICE);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AMBULANCE);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MIEC);
+ EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AIEC);
+ }
+
+ /**
+ * The source to tell where the corresponding @1.3::EmergencyNumber comes from.
+ *
+ * The emergency number has one or more defined emergency number sources.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "EMERGENCY_NUMBER_SOURCE_" }, value = {
+ EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
+ EMERGENCY_NUMBER_SOURCE_SIM,
+ EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG,
+ EMERGENCY_NUMBER_SOURCE_DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EmergencyNumberSources {}
+
+ /**
+ * Bit-field which indicates the number is from the network signaling.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING =
+ EmergencyNumberSource.NETWORK_SIGNALING;
+ /**
+ * Bit-field which indicates the number is from the sim.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_NUMBER_SOURCE_SIM = EmergencyNumberSource.SIM;
+ /** Bit-field which indicates the number is from the modem config. */
+ public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
+ EmergencyNumberSource.MODEM_CONFIG;
+ /**
+ * Bit-field which indicates the number is available as default.
+ *
+ * 112, 911 must always be available; additionally, 000, 08, 110, 999, 118 and 119 must be
+ * available when sim is not present.
+ *
+ * Reference: 3gpp 22.101, Section 10 - Emergency Calls
+ */
+ public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = EmergencyNumberSource.DEFAULT;
+
+ private static final Set<Integer> EMERGENCY_NUMBER_SOURCE_SET;
+ static {
+ EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
+ EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
+ EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_SIM);
+ EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG);
+ EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
+ }
+
+ private final String mNumber;
+ private final String mCountryIso;
+ private final int mEmergencyServiceCategoryBitmask;
+ private final int mEmergencyNumberSourceBitmask;
+
+ /** @hide */
+ public EmergencyNumber(String number, String countryIso,
+ int emergencyServiceCategories,
+ int emergencyNumberSources) {
+ this.mNumber = number;
+ this.mCountryIso = countryIso;
+ this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
+ this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
+ }
+
+ /** @hide */
+ public EmergencyNumber(Parcel source) {
+ mNumber = source.readString();
+ mCountryIso = source.readString();
+ mEmergencyServiceCategoryBitmask = source.readInt();
+ mEmergencyNumberSourceBitmask = source.readInt();
+ }
+
+ /**
+ * Get the dialing number of the emergency number.
+ *
+ * The character in the number string is only the dial pad
+ * character('0'-'9', '*', or '#'). For example: 911.
+ *
+ * @return the dialing number.
+ */
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Get the country code string (lowercase character) in ISO 3166 format of the emergency number.
+ *
+ * @return the country code string (lowercase character) in ISO 3166 format.
+ */
+ public String getCountryIso() {
+ return mCountryIso;
+ }
+
+ /**
+ * Returns the bitmask of emergency service categories of the emergency number.
+ *
+ * @return bitmask of the emergency service categories
+ */
+ public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
+ return mEmergencyServiceCategoryBitmask;
+ }
+
+ /**
+ * Returns the emergency service categories of the emergency number.
+ *
+ * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} is returned and it means the number is in
+ * all categories.
+ *
+ * @return a list of the emergency service categories
+ */
+ public List<Integer> getEmergencyServiceCategories() {
+ List<Integer> categories = new ArrayList<>();
+ if (serviceUnspecified()) {
+ categories.add(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED);
+ return categories;
+ }
+ for (Integer category : EMERGENCY_SERVICE_CATEGORY_SET) {
+ if (isInEmergencyServiceCategories(category)) {
+ categories.add(category);
+ }
+ }
+ return categories;
+ }
+
+ /**
+ * Checks if the emergency service category is unspecified for the emergency number
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}.
+ *
+ * @return {@code true} if the emergency service category is unspecified for the emergency
+ * number {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
+ */
+ private boolean serviceUnspecified() {
+ return mEmergencyServiceCategoryBitmask == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+ }
+
+ /**
+ * Checks if the emergency number is in the supplied emergency service category(s).
+ *
+ * @param categories - the supplied emergency service categories
+ *
+ * @return {@code true} if the emergency number is in the specified emergency service
+ * category(s) or if its emergency service category is
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
+ */
+ public boolean isInEmergencyServiceCategories(@EmergencyServiceCategories int categories) {
+ if (categories == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED) {
+ return serviceUnspecified();
+ }
+ if (serviceUnspecified()) {
+ return true;
+ }
+ return (mEmergencyServiceCategoryBitmask & categories) == categories;
+ }
+
+ /**
+ * Returns the bitmask of the sources of the emergency number.
+ *
+ * @return bitmask of the emergency number sources
+ */
+ public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
+ return mEmergencyNumberSourceBitmask;
+ }
+
+ /**
+ * Returns a list of sources of the emergency number.
+ *
+ * @return a list of emergency number sources
+ */
+ public List<Integer> getEmergencyNumberSources() {
+ List<Integer> sources = new ArrayList<>();
+ for (Integer source : EMERGENCY_NUMBER_SOURCE_SET) {
+ if ((mEmergencyNumberSourceBitmask & source) == source) {
+ sources.add(source);
+ }
+ }
+ return sources;
+ }
+
+ /**
+ * Checks if the emergency number is from the specified emergency number source(s).
+ *
+ * @return {@code true} if the emergency number is from the specified emergency number
+ * source(s); {@code false} otherwise.
+ *
+ * @param sources - the supplied emergency number sources
+ */
+ public boolean isFromSources(@EmergencyNumberSources int sources) {
+ return (mEmergencyNumberSourceBitmask & sources) == sources;
+ }
+
+ @Override
+ /** @hide */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mNumber);
+ dest.writeString(mCountryIso);
+ dest.writeInt(mEmergencyServiceCategoryBitmask);
+ dest.writeInt(mEmergencyNumberSourceBitmask);
+ }
+
+ @Override
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "EmergencyNumber = " + "[Number]" + mNumber + " / [CountryIso]" + mCountryIso
+ + " / [ServiceCategories]"
+ + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
+ + " / [Sources]" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!EmergencyNumber.class.isInstance(o)) {
+ return false;
+ }
+ return (o == this || toString().equals(o.toString()));
+ }
+
+ /**
+ * Calculate the score for display priority.
+ *
+ * A higher display priority score means the emergency number has a higher display priority.
+ * The score is higher if the source is defined for a higher display priority.
+ *
+ * The priority of sources are defined as follows:
+ * EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING >
+ * EMERGENCY_NUMBER_SOURCE_SIM >
+ * EMERGENCY_NUMBER_SOURCE_DEFAULT >
+ * EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG
+ *
+ */
+ private int getDisplayPriorityScore() {
+ int score = 0;
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING)) {
+ score += 1 << 4;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) {
+ score += 1 << 3;
+ }
+ // TODO add a score if the number comes from Google's emergency number database
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) {
+ score += 1 << 1;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG)) {
+ score += 1 << 0;
+ }
+ return score;
+ }
+
+ /**
+ * Compare the display priority for this emergency number and the supplied emergency number.
+ *
+ * @param emergencyNumber the supplied emergency number
+ * @return a negative value if the supplied emergency number has a lower display priority;
+ * a positive value if the supplied emergency number has a higher display priority;
+ * 0 if both have equal display priority.
+ */
+ @Override
+ public int compareTo(EmergencyNumber emergencyNumber) {
+ if (this.getDisplayPriorityScore()
+ > emergencyNumber.getDisplayPriorityScore()) {
+ return -1;
+ } else if (this.getDisplayPriorityScore()
+ < emergencyNumber.getDisplayPriorityScore()) {
+ return 1;
+ } else {
+ /**
+ * TODO if both numbers have the same display priority score, the number matches the
+ * Google's emergency number database has a higher display priority.
+ */
+ return 0;
+ }
+ }
+
+ public static final Parcelable.Creator<EmergencyNumber> CREATOR =
+ new Parcelable.Creator<EmergencyNumber>() {
+ @Override
+ public EmergencyNumber createFromParcel(Parcel in) {
+ return new EmergencyNumber(in);
+ }
+
+ @Override
+ public EmergencyNumber[] newArray(int size) {
+ return new EmergencyNumber[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index f0d3c89..89ef339 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -117,10 +117,14 @@
* @hide
*/
public static final String EXTRA_CONFERENCE = "conference";
+
/**
- * @hide
+ * Boolean extra property set on an {@link ImsCallProfile} to indicate that this call is an
+ * emergency call. The {@link ImsService} sets this on a call to indicate that the network has
+ * identified the call as an emergency call.
*/
- public static final String EXTRA_E_CALL = "e_call";
+ public static final String EXTRA_EMERGENCY_CALL = "e_call";
+
/**
* @hide
*/
@@ -245,7 +249,8 @@
* constants, the values passed for the {@link #EXTRA_CALL_RAT_TYPE} should be strings (e.g.
* "14" vs (int) 14).
* Note: This is used by {@link com.android.internal.telephony.imsphone.ImsPhoneConnection#
- * updateWifiStateFromExtras(Bundle)} to determine whether to set the
+ * updateImsCallRatFromExtras(Bundle)} to determine whether to set the
+ * {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and
* {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
*/
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index a20d4f5..df903cc2 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -16,22 +16,16 @@
package android.telephony.ims;
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.ims.aidl.IImsCallSessionListener;
-
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-import android.telephony.ims.stub.ImsCallSessionImplBase;
import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
+import java.util.Objects;
+
/**
* Provides the call initiation/termination, and media exchange between two IMS endpoints.
* It directly communicates with IMS service which implements the IMS protocol behavior.
@@ -42,7 +36,8 @@
private static final String TAG = "ImsCallSession";
/**
- * Defines IMS call session state. Please use {@link ImsCallSessionImplBase.State} definition.
+ * Defines IMS call session state. Please use
+ * {@link android.telephony.ims.stub.ImsCallSessionImplBase.State} definition.
* This is kept around for capability reasons.
*/
public static class State {
@@ -1027,9 +1022,9 @@
}
/**
- * Sends RTT Upgrade request
+ * Sends RTT Upgrade or downgrade request
*
- * @param to : expected profile
+ * @param to Profile with the RTT flag set to the desired value
*/
public void sendRttModifyRequest(ImsCallProfile to) {
if (mClosed) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 3138180..cecf2e2 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -21,12 +21,11 @@
import android.net.Uri;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.util.Log;
-import android.telephony.ims.ImsReasonInfo;
-
import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
@@ -81,13 +80,14 @@
* Callback class for receiving Registration callback events.
* @hide
*/
- public static class Callback {
+ public static class Callback extends IImsRegistrationCallback.Stub {
/**
* Notifies the framework when the IMS Provider is connected to the IMS network.
*
* @param imsRadioTech the radio access technology. Valid values are defined in
* {@link ImsRegistrationTech}.
*/
+ @Override
public void onRegistered(@ImsRegistrationTech int imsRadioTech) {
}
@@ -97,6 +97,7 @@
* @param imsRadioTech the radio access technology. Valid values are defined in
* {@link ImsRegistrationTech}.
*/
+ @Override
public void onRegistering(@ImsRegistrationTech int imsRadioTech) {
}
@@ -105,6 +106,7 @@
*
* @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
*/
+ @Override
public void onDeregistered(ImsReasonInfo info) {
}
@@ -115,6 +117,7 @@
* @param imsRadioTech The {@link ImsRegistrationTech} type that has failed
* @param info A {@link ImsReasonInfo} that identifies the reason for failure.
*/
+ @Override
public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
ImsReasonInfo info) {
}
@@ -125,6 +128,7 @@
* @param uris new array of subscriber {@link Uri}s that are associated with this IMS
* subscription.
*/
+ @Override
public void onSubscriberAssociatedUriChanged(Uri[] uris) {
}
diff --git a/telephony/java/android/telephony/mbms/GroupCall.java b/telephony/java/android/telephony/mbms/GroupCall.java
new file mode 100644
index 0000000..9aca18e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCall.java
@@ -0,0 +1,176 @@
+/*
+ * 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.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.os.RemoteException;
+import android.telephony.MbmsGroupCallSession;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class used to represent a single MBMS group call. After a call has been started with
+ * {@link MbmsGroupCallSession#startGroupCall},
+ * this class is used to hold information about the call and control it.
+ */
+public class GroupCall implements AutoCloseable {
+ private static final String LOG_TAG = "MbmsGroupCall";
+
+ /**
+ * The state of a group call, reported via
+ * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED})
+ public @interface GroupCallState {}
+ public static final int STATE_STOPPED = 1;
+ public static final int STATE_STARTED = 2;
+ public static final int STATE_STALLED = 3;
+
+ /**
+ * The reason for a call state change, reported via
+ * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "REASON_" },
+ value = {REASON_BY_USER_REQUEST, REASON_FREQUENCY_CONFLICT,
+ REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
+ REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE})
+ public @interface GroupCallStateChangeReason {}
+
+ /**
+ * Indicates that the middleware does not have a reason to provide for the state change.
+ */
+ public static final int REASON_NONE = 0;
+
+ /**
+ * State changed due to a call to {@link #close()} or
+ * {@link MbmsGroupCallSession#startGroupCall}
+ */
+ public static final int REASON_BY_USER_REQUEST = 1;
+
+ // 2 is unused to match up with streaming.
+
+ /**
+ * State changed due to a frequency conflict with another requested call.
+ */
+ public static final int REASON_FREQUENCY_CONFLICT = 3;
+
+ /**
+ * State changed due to the middleware running out of memory
+ */
+ public static final int REASON_OUT_OF_MEMORY = 4;
+
+ /**
+ * State changed due to the device leaving the home carrier's LTE network.
+ */
+ public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5;
+
+ /**
+ * State changed due to the device leaving the area where this call is being broadcast.
+ */
+ public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6;
+
+ private final int mSubscriptionId;
+ private final long mTmgi;
+ private final MbmsGroupCallSession mParentSession;
+ private final InternalGroupCallCallback mCallback;
+ private IMbmsGroupCallService mService;
+
+ /**
+ * @hide
+ */
+ public GroupCall(int subscriptionId,
+ IMbmsGroupCallService service,
+ MbmsGroupCallSession session,
+ long tmgi,
+ InternalGroupCallCallback callback) {
+ mSubscriptionId = subscriptionId;
+ mParentSession = session;
+ mService = service;
+ mTmgi = tmgi;
+ mCallback = callback;
+ }
+
+ /**
+ * Retrieve the TMGI (Temporary Mobile Group Identity) corresponding to this call.
+ */
+ public long getTmgi() {
+ return mTmgi;
+ }
+
+ /**
+ * Send an update to the middleware when the SAI (Service Area Identifier) list and frequency
+ * information of the group call has * changed. Callers must obtain this information from the
+ * wireless carrier independently.
+ * @param saiArray New array of SAIs that the call is available on.
+ * @param frequencyArray New array of frequencies that the call is available on.
+ */
+ public void updateGroupCall(int[] saiArray, int[] frequencyArray) {
+ if (mService == null) {
+ throw new IllegalStateException("No group call service attached");
+ }
+
+ try {
+ mService.updateGroupCall(mSubscriptionId, mTmgi, saiArray, frequencyArray);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Remote process died");
+ mService = null;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ } finally {
+ mParentSession.onGroupCallStopped(this);
+ }
+ }
+
+ /**
+ * Stop this group call. Further operations on this object will fail with an
+ * {@link IllegalStateException}.
+ *
+ * May throw an {@link IllegalStateException}
+ */
+ @Override
+ public void close() {
+ if (mService == null) {
+ throw new IllegalStateException("No group call service attached");
+ }
+
+ try {
+ mService.stopGroupCall(mSubscriptionId, mTmgi);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Remote process died");
+ mService = null;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ } finally {
+ mParentSession.onGroupCallStopped(this);
+ }
+ }
+
+ /** @hide */
+ public InternalGroupCallCallback getCallback() {
+ return mCallback;
+ }
+
+ private void sendErrorToApp(int errorCode, String message) {
+ mCallback.onError(errorCode, message);
+ }
+}
+
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
new file mode 100644
index 0000000..001bb02
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -0,0 +1,87 @@
+/*
+ * 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.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A callback class for use when the application is in a group call. The middleware
+ * will provide updates on the status of the call via this callback.
+ */
+public class GroupCallCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+ MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+ MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+ MbmsErrors.GeneralErrors.ERROR_IN_E911,
+ MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+ MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+ MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+ private @interface GroupCallError{}
+
+ /**
+ * Indicates broadcast signal strength is not available for this call.
+ *
+ * This may be due to the call no longer being available due to geography
+ * or timing (end of service)
+ */
+ public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
+
+ /**
+ * Called by the middleware when it has detected an error condition in this group call. The
+ * possible error codes are listed in {@link MbmsErrors}.
+ * @param errorCode The error code.
+ * @param message A human-readable message generated by the middleware for debugging purposes.
+ */
+ public void onError(@GroupCallError int errorCode, @Nullable String message) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate this call has changed state.
+ *
+ * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
+ * and {@link GroupCall#STATE_STALLED}.
+ */
+ public void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+ @GroupCall.GroupCallStateChangeReason int reason) {
+ // default implementation empty
+ }
+
+ /**
+ * Broadcast Signal Strength updated.
+ *
+ * This signal strength is the BROADCAST signal strength which,
+ * depending on technology in play and it's deployment, may be
+ * stronger or weaker than the traditional UNICAST signal
+ * strength. It a simple int from 0-4 for valid levels or
+ * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
+ * for this call due to timing, geography or popularity.
+ */
+ public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+ // default implementation empty
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
new file mode 100755
index 0000000..844b634
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.telephony.mbms;
+
+/**
+ * @hide
+ */
+oneway interface IGroupCallCallback {
+ void onError(int errorCode, String message);
+ void onGroupCallStateChanged(int state, int reason);
+ void onBroadcastSignalStrengthUpdated(int signalStrength);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
new file mode 100755
index 0000000..1a1c7f8
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
@@ -0,0 +1,33 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+oneway interface IMbmsGroupCallSessionCallback
+{
+ void onError(int errorCode, String message);
+
+ void onAvailableSaisUpdated(in List currentSai, in List availableSais);
+
+ void onServiceInterfaceAvailable(String interfaceName, int index);
+
+ void onMiddlewareReady();
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
new file mode 100644
index 0000000..2910bb3
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
@@ -0,0 +1,96 @@
+/*
+ * 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.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
+ private final GroupCallCallback mAppCallback;
+ private final Executor mExecutor;
+ private volatile boolean mIsStopped = false;
+
+ public InternalGroupCallCallback(GroupCallCallback appCallback,
+ Executor executor) {
+ mAppCallback = appCallback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onError(final int errorCode, final String message) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onError(errorCode, message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onGroupCallStateChanged(final int state, final int reason) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onGroupCallStateChanged(state, reason);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onBroadcastSignalStrengthUpdated(final int signalStrength) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ /** Prevents this callback from calling the app */
+ public void stop() {
+ mIsStopped = true;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
new file mode 100644
index 0000000..4c9cf4d
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
@@ -0,0 +1,116 @@
+/*
+ * 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.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallback.Stub {
+ private final Executor mExecutor;
+ private final MbmsGroupCallSessionCallback mAppCallback;
+ private volatile boolean mIsStopped = false;
+
+ public InternalGroupCallSessionCallback(MbmsGroupCallSessionCallback appCallback,
+ Executor executor) {
+ mAppCallback = appCallback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onError(final int errorCode, final String message) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onError(errorCode, message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onAvailableSaisUpdated(final List currentSais, final List availableSais) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onAvailableSaisUpdated(currentSais, availableSais);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onServiceInterfaceAvailable(final String interfaceName, final int index) {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onServiceInterfaceAvailable(interfaceName, index);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onMiddlewareReady() {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onMiddlewareReady();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ /** Prevents this callback from calling the app */
+ public void stop() {
+ mIsStopped = true;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
new file mode 100644
index 0000000..7da734e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -0,0 +1,99 @@
+/*
+ * 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.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.telephony.MbmsGroupCallSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class that is used to receive information from the middleware on MBMS group-call
+ * services. An instance of this object should be passed into
+ * {@link MbmsGroupCallSession#create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ */
+public class MbmsGroupCallSessionCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+ MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+ MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED,
+ MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE,
+ MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+ MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+ MbmsErrors.GeneralErrors.ERROR_IN_E911,
+ MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+ MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+ MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+ private @interface GroupCallError{}
+
+ /**
+ * Called by the middleware when it has detected an error condition. The possible error codes
+ * are listed in {@link MbmsErrors}.
+ * @param errorCode The error code.
+ * @param message A human-readable message generated by the middleware for debugging purposes.
+ */
+ public void onError(@GroupCallError int errorCode, @Nullable String message) {
+ }
+
+ /**
+ * Indicates that the list of currently available SAIs has been updated. The app may use this
+ * information to filter the list of group calls when displaying available group calls to
+ * the user by matching the SAIs with a list of group calls separately negotiated with the
+ * carrier. The app may also report the aggregate list of SAIs to the group call application
+ * server so that a network entity can determine when, and where to activate the broadcast of
+ * particular group calls.
+ * @param currentSais The available SAIs on the current cell.
+ * @param availableSais A list of lists of available SAIS in neighboring cells, where each list
+ * contains the available SAIs in an individual cell.
+ */
+ public void onAvailableSaisUpdated(List<Integer> currentSais,
+ List<List<Integer>> availableSais) {
+ }
+
+ /**
+ * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
+ * via this callback may be used to establish a data-link interface with the modem before the
+ * middleware is ready.
+ * Note that this method may be called before {@link #onMiddlewareReady()}.
+ *
+ * @param interfaceName The interface name for the data link.
+ * @param index The index for the data link.
+ */
+ public void onServiceInterfaceAvailable(String interfaceName, int index) {
+ }
+
+ /**
+ * Called to indicate that the middleware has been initialized and is ready.
+ *
+ * Before this method is called, calling any method on an instance of
+ * {@link MbmsGroupCallSession} will result in an {@link IllegalStateException} or an error
+ * delivered via {@link #onError(int, String)} with error code
+ * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
+ */
+ public void onMiddlewareReady() {
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 06b2120..95b4d37 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -23,6 +23,7 @@
import android.content.pm.*;
import android.content.pm.ServiceInfo;
import android.telephony.MbmsDownloadSession;
+import android.telephony.MbmsGroupCallSession;
import android.telephony.MbmsStreamingSession;
import android.util.Log;
@@ -59,6 +60,9 @@
case MbmsStreamingSession.MBMS_STREAMING_SERVICE_ACTION:
metaDataKey = MbmsStreamingSession.MBMS_STREAMING_SERVICE_OVERRIDE_METADATA;
break;
+ case MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_ACTION:
+ metaDataKey = MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA;
+ break;
}
if (metaDataKey == null) {
return null;
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
new file mode 100755
index 0000000..721256a
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -0,0 +1,39 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.IGroupCallCallback;
+
+/**
+ * @hide
+ */
+interface IMbmsGroupCallService
+{
+ int initialize(IMbmsGroupCallSessionCallback callback, int subId);
+
+ void stopGroupCall(int subId, long tmgi);
+
+ void updateGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+ in int[] frequencyArray);
+
+ int startGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+ in int[] frequencyArray, IGroupCallCallback callback);
+
+ void dispose(int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
new file mode 100644
index 0000000..3734ca7
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
@@ -0,0 +1,275 @@
+/*
+ * 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.telephony.mbms.vendor;
+
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.IGroupCallCallback;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.vendor.IMbmsGroupCallService.Stub;
+
+import java.util.List;
+
+/**
+ * Base class for MBMS group-call services. The middleware should override this class to implement
+ * its {@link Service} for group calls
+ * Subclasses should call this class's {@link #onBind} method to obtain an {@link IBinder} if they
+ * override {@link #onBind}.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class MbmsGroupCallServiceBase extends Service {
+ private final IBinder mInterface = new Stub() {
+ @Override
+ public int initialize(final IMbmsGroupCallSessionCallback callback,
+ final int subscriptionId) throws RemoteException {
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
+ final int uid = Binder.getCallingUid();
+
+ int result = MbmsGroupCallServiceBase.this.initialize(
+ new MbmsGroupCallSessionCallback() {
+ @Override
+ public void onError(final int errorCode, final String message) {
+ try {
+ if (errorCode == MbmsErrors.UNKNOWN) {
+ throw new IllegalArgumentException(
+ "Middleware cannot send an unknown error.");
+ }
+ callback.onError(errorCode, message);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+
+ @Override
+ public void onAvailableSaisUpdated(final List currentSais,
+ final List availableSais) {
+ try {
+ callback.onAvailableSaisUpdated(currentSais, availableSais);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+
+ @Override
+ public void onServiceInterfaceAvailable(final String interfaceName,
+ final int index) {
+ try {
+ callback.onServiceInterfaceAvailable(interfaceName, index);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+
+ @Override
+ public void onMiddlewareReady() {
+ try {
+ callback.onMiddlewareReady();
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+ }, subscriptionId);
+
+ if (result == MbmsErrors.SUCCESS) {
+ callback.asBinder().linkToDeath(new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }, 0);
+ }
+
+ return result;
+ }
+
+ @Override
+ public void stopGroupCall(int subId, long tmgi) {
+ MbmsGroupCallServiceBase.this.stopGroupCall(subId, tmgi);
+ }
+
+ @Override
+ public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+ int[] frequencyArray) {
+ MbmsGroupCallServiceBase.this.updateGroupCall(
+ subscriptionId, tmgi, saiArray, frequencyArray);
+ }
+
+ @Override
+ public int startGroupCall(final int subscriptionId, final long tmgi, final int[] saiArray,
+ final int[] frequencyArray, final IGroupCallCallback callback)
+ throws RemoteException {
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
+ final int uid = Binder.getCallingUid();
+
+ int result = MbmsGroupCallServiceBase.this.startGroupCall(
+ subscriptionId, tmgi, saiArray, frequencyArray, new GroupCallCallback() {
+ @Override
+ public void onError(final int errorCode, final String message) {
+ try {
+ if (errorCode == MbmsErrors.UNKNOWN) {
+ throw new IllegalArgumentException(
+ "Middleware cannot send an unknown error.");
+ }
+ callback.onError(errorCode, message);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+
+ public void onGroupCallStateChanged(int state, int reason) {
+ try {
+ callback.onGroupCallStateChanged(state, reason);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+
+ public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+ try {
+ callback.onBroadcastSignalStrengthUpdated(signalStrength);
+ } catch (RemoteException e) {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }
+ });
+
+ if (result == MbmsErrors.SUCCESS) {
+ callback.asBinder().linkToDeath(new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ onAppCallbackDied(uid, subscriptionId);
+ }
+ }, 0);
+ }
+
+ return result;
+ }
+
+ @Override
+ public void dispose(int subId) throws RemoteException {
+ MbmsGroupCallServiceBase.this.dispose(subId);
+ }
+ };
+
+ /**
+ * Initialize the group call service for this app and subscription ID, registering the callback.
+ *
+ * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which
+ * will be intercepted and passed to the app as
+ * {@link MbmsErrors.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
+ *
+ * May return any value from {@link MbmsErrors.InitializationErrors}
+ * or {@link MbmsErrors#SUCCESS}. Non-successful error codes will be passed to the app via
+ * {@link IMbmsGroupCallSessionCallback#onError(int, String)}.
+ *
+ * @param callback The callback to use to communicate with the app.
+ * @param subscriptionId The subscription ID to use.
+ */
+ public int initialize(MbmsGroupCallSessionCallback callback, int subscriptionId)
+ throws RemoteException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Starts a particular group call. This method may perform asynchronous work. When
+ * the call is ready for consumption, the middleware should inform the app via
+ * {@link IGroupCallCallback#onGroupCallStateChanged(int, int)}.
+ *
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
+ * @param subscriptionId The subscription id to use.
+ * @param tmgi The TMGI, an identifier for the group call.
+ * @param saiArray An array of SAIs for the group call.
+ * @param frequencyArray An array of frequencies for the group call.
+ * @param callback The callback object on which the app wishes to receive updates.
+ * @return Any error in {@link MbmsErrors.GeneralErrors}
+ */
+ public int startGroupCall(int subscriptionId, long tmgi, int[] saiArray, int[] frequencyArray,
+ GroupCallCallback callback) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Stop the group call identified by {@code tmgi}.
+ *
+ * The callback provided via {@link #startGroupCall} should no longer be
+ * used after this method has called by the app.
+ *
+ * May throw an {@link IllegalStateException}
+ *
+ * @param subscriptionId The subscription id to use.
+ * @param tmgi The TMGI for the call to stop.
+ */
+ public void stopGroupCall(int subscriptionId, long tmgi) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Called when the app receives new SAI and frequency information for the group call identified
+ * by {@code tmgi}.
+ * @param saiArray New array of SAIs that the call is available on.
+ * @param frequencyArray New array of frequencies that the call is available on.
+ */
+ public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+ int[] frequencyArray) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Signals that the app wishes to dispose of the session identified by the
+ * {@code subscriptionId} argument and the caller's uid. No notification back to the
+ * app is required for this operation, and the corresponding callback provided via
+ * {@link #initialize} should no longer be used
+ * after this method has been called by the app.
+ *
+ * May throw an {@link IllegalStateException}
+ *
+ * @param subscriptionId The subscription id to use.
+ */
+ public void dispose(int subscriptionId) throws RemoteException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Indicates that the app identified by the given UID and subscription ID has died.
+ * @param uid the UID of the app, as returned by {@link Binder#getCallingUid()}.
+ * @param subscriptionId The subscription ID the app is using.
+ */
+ public void onAppCallbackDied(int uid, int subscriptionId) {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mInterface;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 86cb1b7..b0c875e 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -100,6 +100,7 @@
public static final int EVENT_DATA_RECONNECT = BASE + 47;
public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+ public static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = BASE + 50;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/IAns.aidl b/telephony/java/com/android/internal/telephony/IAns.aidl
new file mode 100755
index 0000000..6eb8d66
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IAns.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+
+interface IAns {
+
+ /**
+ * Enable or disable Alternative Network service.
+ *
+ * This method should be called to enable or disable
+ * AlternativeNetwork service on the device.
+ *
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param enable enable(True) or disable(False)
+ * @param callingPackage caller's package name
+ * @return returns true if successfully set.
+ */
+ boolean setEnable(boolean enable, String callingPackage);
+
+ /**
+ * is Alternative Network service enabled
+ *
+ * This method should be called to determine if the Alternative Network service is enabled
+ *
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param callingPackage caller's package name
+ */
+ boolean isEnabled(String callingPackage);
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 1ebb697..8681859 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -52,5 +52,6 @@
void onCarrierNetworkChange(in boolean active);
void onUserMobileDataStateChanged(in boolean enabled);
void onPhoneCapabilityChanged(in PhoneCapability capability);
+ void onRadioPowerStateChanged(in int state);
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6521f0b..0ccd748 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -232,5 +232,5 @@
*/
int getSimStateForSlotIndex(int slotIndex);
- boolean isActiveSubId(int subId);
+ boolean isActiveSubId(int subId, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 066db1f..3417da1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -75,116 +75,6 @@
void call(String callingPackage, String number);
/**
- * End call if there is a call in progress, otherwise does nothing.
- *
- * @return whether it hung up
- */
- boolean endCall();
-
- /**
- * End call on particular subId or go to the Home screen
- * @param subId user preferred subId.
- * @return whether it hung up
- */
- boolean endCallForSubscriber(int subId);
-
- /**
- * Answer the currently-ringing call.
- *
- * If there's already a current active call, that call will be
- * automatically put on hold. If both lines are currently in use, the
- * current active call will be ended.
- *
- * TODO: provide a flag to let the caller specify what policy to use
- * if both lines are in use. (The current behavior is hardwired to
- * "answer incoming, end ongoing", which is how the CALL button
- * is specced to behave.)
- *
- * TODO: this should be a oneway call (especially since it's called
- * directly from the key queue thread).
- */
- void answerRingingCall();
-
- /**
- * Answer the currently-ringing call on particular subId .
- *
- * If there's already a current active call, that call will be
- * automatically put on hold. If both lines are currently in use, the
- * current active call will be ended.
- *
- * TODO: provide a flag to let the caller specify what policy to use
- * if both lines are in use. (The current behavior is hardwired to
- * "answer incoming, end ongoing", which is how the CALL button
- * is specced to behave.)
- *
- * TODO: this should be a oneway call (especially since it's called
- * directly from the key queue thread).
- */
- void answerRingingCallForSubscriber(int subId);
-
- /**
- * Silence the ringer if an incoming call is currently ringing.
- * (If vibrating, stop the vibrator also.)
- *
- * It's safe to call this if the ringer has already been silenced, or
- * even if there's no incoming call. (If so, this method will do nothing.)
- *
- * TODO: this should be a oneway call too (see above).
- * (Actually *all* the methods here that return void can
- * probably be oneway.)
- */
- void silenceRinger();
-
- /**
- * Check if we are in either an active or holding call
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is OFFHOOK.
- */
- boolean isOffhook(String callingPackage);
-
- /**
- * Check if a particular subId has an active or holding call
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is OFFHOOK.
- */
- boolean isOffhookForSubscriber(int subId, String callingPackage);
-
- /**
- * Check if an incoming phone call is ringing or call waiting
- * on a particular subId.
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is RINGING.
- */
- boolean isRingingForSubscriber(int subId, String callingPackage);
-
- /**
- * Check if an incoming phone call is ringing or call waiting.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is RINGING.
- */
- boolean isRinging(String callingPackage);
-
- /**
- * Check if the phone is idle.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is IDLE.
- */
- boolean isIdle(String callingPackage);
-
- /**
- * Check if the phone is idle on a particular subId.
- *
- * @param subId user preferred subId.
- * @param callingPackage the name of the package making the call.
- * @return true if the phone state is IDLE.
- */
- boolean isIdleForSubscriber(int subId, String callingPackage);
-
- /**
* Check to see if the radio is on or not.
* @param callingPackage the name of the package making the call.
* @return returns true if the radio is on.
@@ -390,7 +280,7 @@
/**
* Returns the neighboring cell information of the device.
*/
- List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg, int targetSdk);
+ List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
int getCallState();
@@ -817,12 +707,6 @@
IImsConfig getImsConfig(int slotId, int feature);
/**
- * @return true if the IMS resolver is busy resolving a binding and should not be considered
- * available, false if the IMS resolver is idle.
- */
- boolean isResolvingImsBinding();
-
- /**
* @return true if the ImsService to bind to for the slot id specified was set, false otherwise.
*/
boolean setImsService(int slotId, boolean isCarrierImsService, String packageName);
@@ -871,14 +755,15 @@
* Ask the radio to connect to the input network and change selection mode to manual.
*
* @param subId the id of the subscription.
- * @param operatorNumeric the PLMN of the operator to attach to.
- * @param persistSelection Whether the selection will persist until reboot. If true, only allows
+ * @param operatorInfo the operator inforamtion, included the PLMN, long name and short name of
+ * the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true if the request suceeded.
+ * @return {@code true} on success; {@code true} on any failure.
*/
- boolean setNetworkSelectionModeManual(int subId, in String operatorNumeric,
- boolean persistSelection);
+ boolean setNetworkSelectionModeManual(
+ int subId, in OperatorInfo operatorInfo, boolean persisSelection);
/**
* Set the preferred network type.
@@ -923,6 +808,13 @@
*/
boolean isDataEnabled(int subId);
+ /**
+ * Checks if manual network selection is allowed.
+ *
+ * @return {@code true} if manual network selection is allowed, otherwise return {@code false}.
+ */
+ boolean isManualNetworkSelectionAllowed(int subId);
+
/**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
@@ -1592,4 +1484,10 @@
* Return the network selection mode on the subscription with id {@code subId}.
*/
int getNetworkSelectionMode(int subId);
+
+ /**
+ * Return the modem radio power state for slot index.
+ *
+ */
+ int getRadioPowerState(int slotIdex, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 43d56b3..2f40fcc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -79,4 +79,5 @@
void notifyCarrierNetworkChange(in boolean active);
void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
void notifyPhoneCapabilityChanged(in PhoneCapability capability);
+ void notifyRadioPowerStateChanged(in int state);
}
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index d0245a0..a47e2b0 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -21,7 +21,7 @@
import android.os.Parcelable;
/**
- * {@hide}
+ * @hide
*/
public class OperatorInfo implements Parcelable {
public enum State {
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index f9de776..21f3b92 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -176,6 +176,10 @@
// FIXME: This is used to pass a subId via intents, we need to look at its usage, which is
// FIXME: extensive, and see if this should be an array of all active subId's or ...?
+ /**
+ * @Deprecated use {@link android.telephony.SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}
+ * instead.
+ */
public static final String SUBSCRIPTION_KEY = "subscription";
public static final String SUB_SETTING = "subSettings";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index 6bf22a0..8015b07 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -33,6 +33,7 @@
import com.android.internal.telephony.SmsConstants;
import java.io.UnsupportedEncodingException;
+import java.util.Locale;
/**
* Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is
@@ -44,16 +45,34 @@
* Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
*/
private static final String[] LANGUAGE_CODES_GROUP_0 = {
- "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
- "pl", null
+ Locale.GERMAN.getLanguage(), // German
+ Locale.ENGLISH.getLanguage(), // English
+ Locale.ITALIAN.getLanguage(), // Italian
+ Locale.FRENCH.getLanguage(), // French
+ new Locale("es").getLanguage(), // Spanish
+ new Locale("nl").getLanguage(), // Dutch
+ new Locale("sv").getLanguage(), // Swedish
+ new Locale("da").getLanguage(), // Danish
+ new Locale("pt").getLanguage(), // Portuguese
+ new Locale("fi").getLanguage(), // Finnish
+ new Locale("nb").getLanguage(), // Norwegian
+ new Locale("el").getLanguage(), // Greek
+ new Locale("tr").getLanguage(), // Turkish
+ new Locale("hu").getLanguage(), // Hungarian
+ new Locale("pl").getLanguage(), // Polish
+ null
};
/**
* Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
*/
private static final String[] LANGUAGE_CODES_GROUP_2 = {
- "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
- null, null
+ new Locale("cs").getLanguage(), // Czech
+ new Locale("he").getLanguage(), // Hebrew
+ new Locale("ar").getLanguage(), // Arabic
+ new Locale("ru").getLanguage(), // Russian
+ new Locale("is").getLanguage(), // Icelandic
+ null, null, null, null, null, null, null, null, null, null, null
};
private static final char CARRIAGE_RETURN = 0x0d;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
index 0fabc2f..541ca8d 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 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/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 4790b75..6b3df94 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -93,11 +93,23 @@
* converted. If the array size is more than needed, the rest of array remains unchanged.
*/
public static void bcdToBytes(String bcd, byte[] bytes) {
+ bcdToBytes(bcd, bytes, 0);
+ }
+
+ /**
+ * Converts BCD string to bytes and put it into the given byte array.
+ *
+ * @param bcd This should have an even length. If not, an "0" will be appended to the string.
+ * @param bytes If the array size is less than needed, the rest of the BCD string isn't be
+ * converted. If the array size is more than needed, the rest of array remains unchanged.
+ * @param offset the offset into the bytes[] to fill the data
+ */
+ public static void bcdToBytes(String bcd, byte[] bytes, int offset) {
if (bcd.length() % 2 != 0) {
bcd += "0";
}
- int size = Math.min(bytes.length * 2, bcd.length());
- for (int i = 0, j = 0; i + 1 < size; i += 2, j++) {
+ int size = Math.min((bytes.length - offset) * 2, bcd.length());
+ for (int i = 0, j = offset; i + 1 < size; i += 2, j++) {
bytes[j] = (byte) (charToByte(bcd.charAt(i + 1)) << 4 | charToByte(bcd.charAt(i)));
}
}
@@ -125,6 +137,20 @@
}
/**
+ * Convert a 5 or 6 - digit PLMN string to a nibble-swizzled encoding as per 24.008 10.5.1.3
+ *
+ * @param plmn the PLMN to convert
+ * @param data a byte array for the output
+ * @param offset the offset into data to start writing
+ */
+ public static void stringToBcdPlmn(final String plmn, byte[] data, int offset) {
+ char digit6 = (plmn.length() > 5) ? plmn.charAt(5) : 'F';
+ data[offset] = (byte) (charToByte(plmn.charAt(1)) << 4 | charToByte(plmn.charAt(0)));
+ data[offset + 1] = (byte) (charToByte(digit6) << 4 | charToByte(plmn.charAt(2)));
+ data[offset + 2] = (byte) (charToByte(plmn.charAt(4)) << 4 | charToByte(plmn.charAt(3)));
+ }
+
+ /**
* Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH
*/
public static String
@@ -844,7 +870,7 @@
}
/**
- * Converts a character of [0-9a-aA-F] to its hex value in a byte. If the character is not a
+ * Converts a character of [0-9a-fA-F] to its hex value in a byte. If the character is not a
* hex number, 0 will be returned.
*/
private static byte charToByte(char c) {
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 0b8a02a..4d765d3 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -37,7 +37,8 @@
"junit.framework",
],
- droiddoc_options: ["stubsourceonly"],
+ droiddoc_options: ["-stubsourceonly"],
+ metalava_enabled: false,
compile_dex: true,
}
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 5eba017..37158e5 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -26,5 +26,6 @@
],
srcs_lib_whitelist_pkgs: ["android"],
+ metalava_enabled: false,
compile_dex: true,
}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index ea615b9..0a0d50c 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -40,7 +40,8 @@
"junit.textui",
],
- droiddoc_options: ["stubsourceonly"],
+ droiddoc_options: ["-stubsourceonly"],
+ metalava_enabled: false,
compile_dex: true
}
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 4c68c8b..94294f6 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -10,9 +10,5 @@
LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 6ce66f0..639ed7d 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -245,8 +245,14 @@
mIterationCycle = false;
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
- String appPkgName = mNameToIntent.get(launch.getApp())
- .getComponent().getPackageName();
+ Intent startIntent = mNameToIntent.get(launch.getApp());
+ if (startIntent == null) {
+ Log.w(TAG, "App does not exist: " + launch.getApp());
+ mResult.putString(mNameToResultKey.get(launch.getApp()),
+ "App does not exist");
+ continue;
+ }
+ String appPkgName = startIntent.getComponent().getPackageName();
if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(VERIFY_FILTER, appPkgName));
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
index a847e8f..a9f01ed 100644
--- a/tests/DexLoggerIntegrationTests/AndroidManifest.xml
+++ b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
@@ -17,10 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.dexloggertest">
- <!-- Tests feature introduced in P (27) -->
+ <!-- Tests feature introduced in P (28) -->
<uses-sdk
- android:minSdkVersion="27"
- android:targetSdkVersion="27" />
+ android:minSdkVersion="28"
+ android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.READ_LOGS" />
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index fe65ecc..a6c21db 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -7,8 +7,6 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- bouncycastle \
- conscrypt \
android.test.base \
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk
index e827ec2..43bf024 100644
--- a/tests/RemoteDisplayProvider/Android.mk
+++ b/tests/RemoteDisplayProvider/Android.mk
@@ -18,9 +18,9 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := RemoteDisplayProviderTest
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := system_current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay.stubs
+LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index e529b93..132135d 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -38,6 +38,7 @@
libbacktrace \
libbase \
libbinder \
+ libbinderthreadstate \
libc++ \
libcrypto \
libcutils \
@@ -62,7 +63,8 @@
libunwindstack \
libutilscallstack \
libziparchive \
- libz
+ libz \
+ netd_aidl_interface-cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
@@ -91,7 +93,8 @@
liblog \
libcutils \
libnativehelper \
- libnetdaidl
+ libnetdaidl \
+ netd_aidl_interface-cpp
LOCAL_STATIC_LIBRARIES := \
libpcap \
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index ba1a2ea..6dae3f1 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -44,6 +44,7 @@
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.NETWORK_STACK" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
index 312b3d1..a592809 100644
--- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.NetworkUtils;
@@ -37,6 +38,7 @@
import java.io.ByteArrayOutputStream;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -56,6 +58,8 @@
private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
SERVER_ADDR, PREFIX_LENGTH);
+ private static final String HOSTNAME = "testhostname";
+ private static final short MTU = 1500;
// Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
// doesn't use == instead of equals when comparing addresses.
private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
@@ -960,7 +964,8 @@
assertTrue(msg, Arrays.equals(expected, actual));
}
- public void checkBuildOfferPacket(int leaseTimeSecs) throws Exception {
+ public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname)
+ throws Exception {
final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2);
final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000);
final int transactionId = 0xdeadbeef;
@@ -971,7 +976,8 @@
CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */,
BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */,
Collections.singletonList(SERVER_ADDR) /* dnsServers */,
- SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, false /* metered */);
+ SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname,
+ false /* metered */, MTU);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// BOOTP headers
@@ -1027,12 +1033,22 @@
// Nameserver
bos.write(new byte[] { (byte) 0x06, (byte) 0x04 });
bos.write(SERVER_ADDR.getAddress());
+ // Hostname
+ if (hostname != null) {
+ bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()});
+ bos.write(hostname.getBytes(Charset.forName("US-ASCII")));
+ }
+ // MTU
+ bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 });
+ bos.write(shortToByteArray(MTU));
// End options.
bos.write(0xff);
- final byte[] expected = bos.toByteArray();
- assertTrue((expected.length & 1) == 0);
+ if ((bos.size() & 1) != 0) {
+ bos.write(0x00);
+ }
+ final byte[] expected = bos.toByteArray();
final byte[] actual = new byte[packet.limit()];
packet.get(actual);
final String msg = "Expected:\n " + HexDump.dumpHexString(expected) +
@@ -1042,13 +1058,18 @@
@Test
public void testOfferPacket() throws Exception {
- checkBuildOfferPacket(3600);
- checkBuildOfferPacket(Integer.MAX_VALUE);
- checkBuildOfferPacket(0x80000000);
- checkBuildOfferPacket(INFINITE_LEASE);
+ checkBuildOfferPacket(3600, HOSTNAME);
+ checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME);
+ checkBuildOfferPacket(0x80000000, HOSTNAME);
+ checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME);
+ checkBuildOfferPacket(3600, null);
}
private static byte[] intToByteArray(int val) {
return ByteBuffer.allocate(4).putInt(val).array();
}
+
+ private static byte[] shortToByteArray(short val) {
+ return ByteBuffer.allocate(2).putShort(val).array();
+ }
}
diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java
index 45a50d9..df34c73 100644
--- a/tests/net/java/android/net/dhcp/DhcpServerTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpServerTest.java
@@ -17,6 +17,7 @@
package android.net.dhcp;
import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
+import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
import static android.net.dhcp.DhcpPacket.INADDR_ANY;
import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
@@ -87,6 +88,7 @@
Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
private static final long TEST_LEASE_TIME_SECS = 3600L;
private static final int TEST_MTU = 1500;
+ private static final String TEST_HOSTNAME = "testhostname";
private static final int TEST_TRANSACTION_ID = 123;
private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
@@ -96,7 +98,10 @@
private static final long TEST_CLOCK_TIME = 1234L;
private static final int TEST_LEASE_EXPTIME_SECS = 3600;
private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
- TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS*1000L + TEST_CLOCK_TIME, null /* hostname */);
+ TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
+ null /* hostname */);
+ private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
+ TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
@NonNull @Mock
private Dependencies mDeps;
@@ -217,15 +222,17 @@
public void testRequest_Selecting_Ack() throws Exception {
when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
- eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
- .thenReturn(TEST_LEASE);
+ eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
+ .thenReturn(TEST_LEASE_WITH_HOSTNAME);
final DhcpRequestPacket request = makeRequestSelectingPacket();
+ request.mHostName = TEST_HOSTNAME;
+ request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
mServer.processPacket(request, DHCP_CLIENT);
assertResponseSentTo(TEST_CLIENT_ADDR);
final DhcpAckPacket packet = assertAck(getPacket());
- assertMatchesTestLease(packet);
+ assertMatchesTestLease(packet, TEST_HOSTNAME);
}
@Test
@@ -270,14 +277,18 @@
* - other request states (init-reboot/renewing/rebinding)
*/
- private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
+ private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
assertMatchesClient(packet);
assertFalse(packet.hasExplicitClientId());
assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
assertNotNull(packet.mLeaseTime);
assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
- assertNull(packet.mHostName);
+ assertEquals(hostname, packet.mHostName);
+ }
+
+ private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
+ assertMatchesTestLease(packet, null);
}
private void assertMatchesClient(@NonNull DhcpPacket packet) {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/android/net/ip/IpServerTest.java
similarity index 71%
rename from tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
rename to tests/net/java/android/net/ip/IpServerTest.java
index 5934653..cff0b54 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.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.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 @@
@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 @@
@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 @@
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 @@
@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 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 @@
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 @@
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 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 @@
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 @@
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 @@
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 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 @@
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 @@
/**
* 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 @@
* @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/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
new file mode 100644
index 0000000..122edba
--- /dev/null
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -0,0 +1,327 @@
+/*
+ * 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.net.netlink;
+
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_RCVTIMEO;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.netlink.StructNlMsgHdr;
+import android.os.Process;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.system.Os;
+import android.system.StructTimeval;
+import android.util.Log;
+import java.io.FileDescriptor;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InetDiagSocketTest {
+ private final String TAG = "InetDiagSocketTest";
+ private ConnectivityManager mCm;
+ private Context mContext;
+ private final static int SOCKET_TIMEOUT_MS = 100;
+
+ @Before
+ public void setUp() throws Exception {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = instrumentation.getTargetContext();
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ private class Connection {
+ public int socketDomain;
+ public int socketType;
+ public InetAddress localAddress;
+ public InetAddress remoteAddress;
+ public InetAddress localhostAddress;
+ public InetSocketAddress local;
+ public InetSocketAddress remote;
+ public int protocol;
+ public FileDescriptor localFd;
+ public FileDescriptor remoteFd;
+
+ public FileDescriptor createSocket() throws Exception {
+ return Os.socket(socketDomain, socketType, protocol);
+ }
+
+ public Connection(String to, String from) throws Exception {
+ remoteAddress = InetAddress.getByName(to);
+ if (from != null) {
+ localAddress = InetAddress.getByName(from);
+ } else {
+ localAddress = (remoteAddress instanceof Inet4Address) ?
+ Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
+ }
+ if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
+ socketDomain = AF_INET;
+ localhostAddress = Inet4Address.getByName("localhost");
+ } else {
+ socketDomain = AF_INET6;
+ localhostAddress = Inet6Address.getByName("::");
+ }
+ }
+
+ public void close() throws Exception {
+ Os.close(localFd);
+ }
+ }
+
+ private class TcpConnection extends Connection {
+ public TcpConnection(String to, String from) throws Exception {
+ super(to, from);
+ protocol = IPPROTO_TCP;
+ socketType = SOCK_STREAM;
+
+ remoteFd = createSocket();
+ Os.bind(remoteFd, remoteAddress, 0);
+ Os.listen(remoteFd, 10);
+ int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
+
+ localFd = createSocket();
+ Os.bind(localFd, localAddress, 0);
+ Os.connect(localFd, remoteAddress, remotePort);
+
+ local = (InetSocketAddress) Os.getsockname(localFd);
+ remote = (InetSocketAddress) Os.getpeername(localFd);
+ }
+
+ public void close() throws Exception {
+ super.close();
+ Os.close(remoteFd);
+ }
+ }
+ private class UdpConnection extends Connection {
+ public UdpConnection(String to, String from) throws Exception {
+ super(to, from);
+ protocol = IPPROTO_UDP;
+ socketType = SOCK_DGRAM;
+
+ remoteFd = null;
+ localFd = createSocket();
+ Os.bind(localFd, localAddress, 0);
+
+ Os.connect(localFd, remoteAddress, 7);
+ local = (InetSocketAddress) Os.getsockname(localFd);
+ remote = new InetSocketAddress(remoteAddress, 7);
+ }
+ }
+
+ private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, boolean expectSuccess) {
+ final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID;
+ final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
+ assertEquals(expectedUid, uid);
+ }
+
+ private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
+ UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
+ conn.localAddress.getHostAddress());
+ final int localPort = udp.local.getPort();
+ udp.close();
+ return localPort;
+ }
+
+ public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
+ /**
+ * For TCP connections, create a test connection and verify that this
+ * {protocol, local, remote} socket result in receiving a valid UID.
+ */
+ TcpConnection tcp = new TcpConnection(to, from);
+ checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
+ checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
+ checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
+ checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
+ tcp.close();
+
+ /**
+ * For UDP connections, either a complete match {protocol, local, remote} or a
+ * partial match {protocol, local} should return a valid UID.
+ */
+ UdpConnection udp = new UdpConnection(to,from);
+ checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
+ checkConnectionOwnerUid(udp.protocol, udp.local, new InetSocketAddress(0), true);
+ checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
+ checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
+ udp.remote, false);
+ udp.close();
+ }
+
+ @Test
+ public void testGetConnectionOwnerUid() throws Exception {
+ checkGetConnectionOwnerUid("::", null);
+ checkGetConnectionOwnerUid("::", "::");
+ checkGetConnectionOwnerUid("0.0.0.0", null);
+ checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
+ checkGetConnectionOwnerUid("127.0.0.1", null);
+ checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
+ checkGetConnectionOwnerUid("::1", null);
+ checkGetConnectionOwnerUid("::1", "::1");
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "02" + // family = AF_INET
+ "11" + // protcol = IPPROTO_UDP
+ "00" + // idiag_ext
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "a5de" + // idiag_sport = 42462
+ "b971" + // idiag_dport = 47473
+ "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
+ "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+ private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
+
+ @Test
+ public void testInetDiagReqV2UdpInet4() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
+ 42462);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+ 47473);
+ final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP));
+ assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0100" + // flags = NLM_F_REQUEST
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "0a" + // family = AF_INET6
+ "06" + // protcol = IPPROTO_TCP
+ "00" + // idiag_ext
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "a5de" + // idiag_sport = 42462
+ "b971" + // idiag_dport = 47473
+ "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+ "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+ private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
+
+ @Test
+ public void testInetDiagReqV2TcpInet6() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(
+ InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+ 47473);
+ byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
+ NLM_F_REQUEST);
+
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_MSG_HEX =
+ // struct nlmsghdr
+ "58000000" + // length = 88
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0200" + // flags = NLM_F_MULTI
+ "00000000" + // seqno
+ "f5220000" + // pid (0 == kernel)
+ // struct inet_diag_msg
+ "0a" + // family = AF_INET6
+ "01" + // idiag_state
+ "00" + // idiag_timer
+ "00" + // idiag_retrans
+ // inet_diag_sockid
+ "a817" + // idiag_sport = 43031
+ "960f" + // idiag_dport = 38415
+ "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+ "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
+ "00000000" + // idiag_expires
+ "00000000" + // idiag_rqueue
+ "00000000" + // idiag_wqueue
+ "a3270000" + // idiag_uid
+ "A57E1900"; // idiag_inode
+ private static final byte[] INET_DIAG_MSG_BYTES =
+ HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
+
+ @Test
+ public void testParseInetDiagResponse() throws Exception {
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
+ assertNotNull(msg);
+
+ assertTrue(msg instanceof InetDiagMessage);
+ final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
+ assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
+
+ final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
+ assertNotNull(hdr);
+ assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
+ assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
+ assertEquals(0, hdr.nlmsg_seq);
+ assertEquals(8949, hdr.nlmsg_pid);
+ }
+}
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
index d46facf..8604860 100644
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -44,6 +44,8 @@
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
final SharedLog logLevel2b = logTop.forSubComponent("twoB");
logLevel2b.e("2b or not 2b");
+ logLevel2b.e("No exception", null);
+ logLevel2b.e("Wait, here's one", new Exception("Test"));
logLevel2a.w("second post?");
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
@@ -54,6 +56,9 @@
final String[] expected = {
" - MARK first post!",
" - [twoB] ERROR 2b or not 2b",
+ " - [twoB] ERROR No exception",
+ // No stacktrace in shared log, only in logcat
+ " - [twoB] ERROR Wait, here's one: Test",
" - [twoA] WARN second post?",
" - still logging",
" - [twoA.three] 3 >> 2",
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e3db7e8..1c77fcc 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -79,6 +79,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -248,7 +249,7 @@
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
- MockContext(Context base) {
+ MockContext(Context base, ContentProvider settingsProvider) {
super(base);
mResources = spy(base.getResources());
@@ -260,7 +261,7 @@
});
mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@Override
@@ -1048,7 +1049,9 @@
Looper.prepare();
}
- mServiceContext = new MockContext(InstrumentationRegistry.getContext());
+ FakeSettingsProvider.clearSettingsProvider();
+ mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
+ new FakeSettingsProvider());
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -1067,13 +1070,13 @@
// Ensure that the default setting for Captive Portals is used for most tests
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- setMobileDataAlwaysOn(false);
+ setAlwaysOnNetworks(false);
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
}
@After
public void tearDown() throws Exception {
- setMobileDataAlwaysOn(false);
+ setAlwaysOnNetworks(false);
if (mCellNetworkAgent != null) {
mCellNetworkAgent.disconnect();
mCellNetworkAgent = null;
@@ -1086,6 +1089,7 @@
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+ FakeSettingsProvider.clearSettingsProvider();
}
private static int transportToLegacyType(int transport) {
@@ -2023,7 +2027,7 @@
@Test
public void testNetworkGoesIntoBackgroundAfterLinger() {
- setMobileDataAlwaysOn(true);
+ setAlwaysOnNetworks(true);
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities()
.build();
@@ -2768,10 +2772,10 @@
Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
}
- private void setMobileDataAlwaysOn(boolean enable) {
+ private void setAlwaysOnNetworks(boolean enable) {
ContentResolver cr = mServiceContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
- mService.updateMobileDataAlwaysOn();
+ mService.updateAlwaysOnNetworks();
waitForIdle();
}
@@ -2793,7 +2797,7 @@
public void testBackgroundNetworks() throws Exception {
// Create a background request. We can't do this ourselves because ConnectivityService
// doesn't have an API for it. So just turn on mobile data always on.
- setMobileDataAlwaysOn(true);
+ setAlwaysOnNetworks(true);
final NetworkRequest request = new NetworkRequest.Builder().build();
final NetworkRequest fgRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -2991,7 +2995,7 @@
// Turn on mobile data always on. The factory starts looking again.
testFactory.expectAddRequests(1);
- setMobileDataAlwaysOn(true);
+ setAlwaysOnNetworks(true);
testFactory.waitForNetworkRequests(2);
assertTrue(testFactory.getMyStartRequested());
@@ -3011,7 +3015,7 @@
// Turn off mobile data always on and expect the request to disappear...
testFactory.expectRemoveRequests(1);
- setMobileDataAlwaysOn(false);
+ setAlwaysOnNetworks(false);
testFactory.waitForNetworkRequests(1);
// ... and cell data to be torn down.
@@ -4532,4 +4536,78 @@
mCellNetworkAgent.disconnect();
mCm.unregisterNetworkCallback(networkCallback);
}
+
+ @Test
+ public void testDataActivityTracking() throws RemoteException {
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ reset(mNetworkManagementService);
+ mCellNetworkAgent.connect(true);
+ networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_MOBILE));
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+
+ // Network switch
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.connect(true);
+ networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_WIFI));
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME));
+
+ // Disconnect wifi and switch back to cell
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ assertNoCallbacks(networkCallback);
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_MOBILE));
+
+ // reconnect wifi
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ mWiFiNetworkAgent.connect(true);
+ networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+
+ // Disconnect cell
+ reset(mNetworkManagementService);
+ mCellNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
+ // sent as network being switched. Ensure rule removal for cell will not be triggered
+ // unexpectedly before network being removed.
+ waitForIdle();
+ verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
+ verify(mNetworkManagementService, times(1)).removeNetwork(
+ eq(mCellNetworkAgent.getNetwork().netId));
+
+ // Disconnect wifi
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.disconnect();
+ waitFor(cv);
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+
+ // Clean up
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 99a5a69..9b919abf 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@@ -34,8 +36,10 @@
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
+import android.net.IpSecTransform;
import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
+import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkUtils;
@@ -62,16 +66,17 @@
private static final int TEST_SPI = 0xD1201D;
- private final String mDestinationAddr;
private final String mSourceAddr;
+ private final String mDestinationAddr;
private final LinkAddress mLocalInnerAddress;
+ private final int mFamily;
@Parameterized.Parameters
public static Collection ipSecConfigs() {
return Arrays.asList(
new Object[][] {
- {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
- {"2601::2", "2601::10", "2001:db8::1/64"}
+ {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
+ {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
});
}
@@ -129,12 +134,14 @@
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
+ private static final int REMOTE_ENCAP_PORT = 4500;
public IpSecServiceParameterizedTest(
- String sourceAddr, String destAddr, String localInnerAddr) {
+ String sourceAddr, String destAddr, String localInnerAddr, int family) {
mSourceAddr = sourceAddr;
mDestinationAddr = destAddr;
mLocalInnerAddress = new LinkAddress(localInnerAddr);
+ mFamily = family;
}
@Before
@@ -157,6 +164,8 @@
.thenReturn(AppOpsManager.MODE_IGNORED);
}
+ //TODO: Add a test to verify SPI.
+
@Test
public void testIpSecServiceReserveSpi() throws Exception {
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
@@ -257,6 +266,47 @@
config.setAuthentication(AUTH_ALGO);
}
+ private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
+ config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
+ config.setEncapSocketResourceId(resourceId);
+ config.setEncapRemotePort(REMOTE_ENCAP_PORT);
+ }
+
+ private void verifyTransformNetdCalledForCreatingSA(
+ IpSecConfig config, IpSecTransformResponse resp) throws Exception {
+ verifyTransformNetdCalledForCreatingSA(config, resp, 0);
+ }
+
+ private void verifyTransformNetdCalledForCreatingSA(
+ IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
+ IpSecAlgorithm auth = config.getAuthentication();
+ IpSecAlgorithm crypt = config.getEncryption();
+ IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
+
+ verify(mMockNetd, times(1))
+ .ipSecAddSecurityAssociation(
+ eq(mUid),
+ eq(config.getMode()),
+ eq(config.getSourceAddress()),
+ eq(config.getDestinationAddress()),
+ eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
+ eq(TEST_SPI),
+ eq(0),
+ eq(0),
+ eq((auth != null) ? auth.getName() : ""),
+ eq((auth != null) ? auth.getKey() : new byte[] {}),
+ eq((auth != null) ? auth.getTruncationLengthBits() : 0),
+ eq((crypt != null) ? crypt.getName() : ""),
+ eq((crypt != null) ? crypt.getKey() : new byte[] {}),
+ eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
+ eq((authCrypt != null) ? authCrypt.getName() : ""),
+ eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
+ eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
+ eq(config.getEncapType()),
+ eq(encapSocketPort),
+ eq(config.getEncapRemotePort()));
+ }
+
@Test
public void testCreateTransform() throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
@@ -267,28 +317,7 @@
mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
- verify(mMockNetd)
- .ipSecAddSecurityAssociation(
- eq(mUid),
- anyInt(),
- anyString(),
- anyString(),
- anyInt(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
- eq(AUTH_KEY),
- anyInt(),
- eq(IpSecAlgorithm.CRYPT_AES_CBC),
- eq(CRYPT_KEY),
- anyInt(),
- eq(""),
- eq(new byte[] {}),
- eq(0),
- anyInt(),
- anyInt(),
- anyInt());
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
}
@Test
@@ -302,28 +331,59 @@
mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
- verify(mMockNetd)
- .ipSecAddSecurityAssociation(
- eq(mUid),
- anyInt(),
- anyString(),
- anyString(),
- anyInt(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- eq(""),
- eq(new byte[] {}),
- eq(0),
- eq(""),
- eq(new byte[] {}),
- eq(0),
- eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
- eq(AEAD_KEY),
- anyInt(),
- anyInt(),
- anyInt(),
- anyInt());
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
+ }
+
+ @Test
+ public void testCreateTransportModeTransformWithEncap() throws Exception {
+ IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+ addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
+
+ if (mFamily == AF_INET) {
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ assertEquals(IpSecManager.Status.OK, createTransformResp.status);
+
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
+ } else {
+ try {
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+
+ @Test
+ public void testCreateTunnelModeTransformWithEncap() throws Exception {
+ IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+ addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
+
+ if (mFamily == AF_INET) {
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ assertEquals(IpSecManager.Status.OK, createTransformResp.status);
+
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
+ } else {
+ try {
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 0d3b8e4..a6ed9f2 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -33,6 +33,7 @@
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -75,6 +76,9 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+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.NetworkConstants;
@@ -84,6 +88,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.INetworkManagementService;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -99,10 +104,8 @@
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;
@@ -147,6 +150,7 @@
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+ @Mock private DhcpServer mDhcpServer;
@Mock private INetd mNetd;
private final MockTetheringDependencies mTetheringDependencies =
@@ -190,7 +194,7 @@
public class MockTetheringDependencies extends TetheringDependencies {
StateMachine upstreamNetworkMonitorMasterSM;
- ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ ArrayList<IpServer> ipv6CoordinatorNotifyList;
int isTetheringSupportedCalls;
public void reset() {
@@ -213,29 +217,41 @@
@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;
- }
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies() {
+ @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);
+ }
- @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
+ public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+ DhcpServingParams params, SharedLog log) {
+ return mDhcpServer;
+ }
+ };
}
@Override
@@ -328,6 +344,7 @@
mServiceContext = new MockContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
mIntents = new Vector<>();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -338,12 +355,16 @@
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTetheringDependencies.reset();
- mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
- mLooper.getLooper(), mSystemProperties,
- mTetheringDependencies);
+ mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
}
+ private Tethering makeTethering() {
+ return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
+ mLooper.getLooper(), mSystemProperties,
+ mTetheringDependencies);
+ }
+
@After
public void tearDown() {
mServiceContext.unregisterReceiver(mBroadcastReceiver);
@@ -458,9 +479,9 @@
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 +578,18 @@
}
/**
- * 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);
@@ -592,6 +613,18 @@
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
+ verify(mDhcpServer, times(1)).start();
+ }
+
+ @Test
+ public void workingMobileUsbTethering_IPv4LegacyDhcp() {
+ Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
+ mTethering = makeTethering();
+ final NetworkState upstreamState = buildMobileIPv4UpstreamState();
+ runUsbTethering(upstreamState);
+ sendIPv6TetherUpdates(upstreamState);
+
+ verify(mDhcpServer, never()).start();
}
@Test
@@ -615,6 +648,7 @@
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mRouterAdvertisementDaemon, times(1)).start();
+ verify(mDhcpServer, times(1)).start();
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -628,6 +662,7 @@
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mDhcpServer, times(1)).start();
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
TEST_XLAT_MOBILE_IFNAME);
@@ -644,6 +679,7 @@
runUsbTethering(upstreamState);
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mDhcpServer, times(1)).start();
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// Then 464xlat comes up
@@ -666,6 +702,8 @@
// Forwarding was not re-added for v6 (still times(1))
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ // DHCP not restarted on downstream (still times(1))
+ verify(mDhcpServer, times(1)).start();
}
@Test
@@ -812,7 +850,7 @@
// 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/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index bb31230..5217784 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -225,13 +225,4 @@
final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
assertFalse(cfg.enableLegacyDhcpServer);
}
-
- @Test
- public void testNewDhcpServerDefault() {
- Settings.Global.putString(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, null);
-
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
- // TODO: change to false when new server is promoted to default
- assertTrue(cfg.enableLegacyDhcpServer);
- }
}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 48cfc44..750fb56 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -120,7 +120,6 @@
"util/BigBuffer.cpp",
"util/Files.cpp",
"util/Util.cpp",
- "ConfigDescription.cpp",
"Debug.cpp",
"DominatorTree.cpp",
"Flags.cpp",
@@ -130,7 +129,6 @@
"java/ManifestClassGenerator.cpp",
"java/ProguardRules.cpp",
"LoadedApk.cpp",
- "Locale.cpp",
"Resource.cpp",
"ResourceParser.cpp",
"ResourceTable.cpp",
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index c9987b8..b165c6b 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -2,10 +2,19 @@
include $(CLEAR_VARS)
+aapt2_results := $(call intermediates-dir-for,PACKAGING,aapt2_run_host_unit_tests)/result.xml
+
# Target for running host unit tests on post/pre-submit.
.PHONY: aapt2_run_host_unit_tests
-aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
-aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
- -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+aapt2_run_host_unit_tests: $(aapt2_results)
+
+$(call dist-for-goals,aapt2_run_host_unit_tests,$(aapt2_results):gtest/aapt2_host_unit_tests_result.xml)
+
+# Always run the tests again, even if they haven't changed
+$(aapt2_results): .KATI_IMPLICIT_OUTPUTS := $(aapt2_results)-nocache
+$(aapt2_results): $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+ -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests --gtest_output=xml:$@ > /dev/null 2>&1
+
+aapt2_results :=
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/DominatorTree.cpp b/tools/aapt2/DominatorTree.cpp
index 118a385..ff18033 100644
--- a/tools/aapt2/DominatorTree.cpp
+++ b/tools/aapt2/DominatorTree.cpp
@@ -19,8 +19,9 @@
#include <algorithm>
#include "android-base/logging.h"
+#include "androidfw/ConfigDescription.h"
-#include "ConfigDescription.h"
+using ::android::ConfigDescription;
namespace aapt {
diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp
index efc523f..fe4f951 100644
--- a/tools/aapt2/DominatorTree_test.cpp
+++ b/tools/aapt2/DominatorTree_test.cpp
@@ -23,6 +23,8 @@
#include "test/Test.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
+
namespace aapt {
namespace {
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index 23ec5ab..f1903a5 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,2 +1,3 @@
set noparent
toddke@google.com
+rtmitchell@google.com
\ No newline at end of file
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 6fcf0f6..1c1aedd 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -24,10 +24,10 @@
#include <tuple>
#include <vector>
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "utils/JenkinsHash.h"
-#include "ConfigDescription.h"
#include "Source.h"
namespace aapt {
@@ -171,7 +171,7 @@
ResourceName name;
// Configuration
- ConfigDescription config;
+ android::ConfigDescription config;
// Type
Type type;
@@ -189,7 +189,7 @@
*/
struct ResourceKey {
ResourceName name;
- ConfigDescription config;
+ android::ConfigDescription config;
};
bool operator<(const ResourceKey& a, const ResourceKey& b);
@@ -201,16 +201,16 @@
*/
struct ResourceKeyRef {
ResourceNameRef name;
- ConfigDescription config;
+ android::ConfigDescription config;
ResourceKeyRef() = default;
- ResourceKeyRef(const ResourceNameRef& n, const ConfigDescription& c)
+ ResourceKeyRef(const ResourceNameRef& n, const android::ConfigDescription& c)
: name(n), config(c) {}
/**
* Prevent taking a reference to a temporary. This is bad.
*/
- ResourceKeyRef(ResourceName&& n, const ConfigDescription& c) = delete;
+ ResourceKeyRef(ResourceName&& n, const android::ConfigDescription& c) = delete;
};
bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 7f48544..39ca80b 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -34,6 +34,7 @@
using ::aapt::ResourceUtils::StringBuilder;
using ::aapt::text::Utf8Iterator;
+using ::android::ConfigDescription;
using ::android::StringPiece;
namespace aapt {
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index fb9dbd0..6cc7b76 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -20,9 +20,9 @@
#include <memory>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
-#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
@@ -53,7 +53,7 @@
class ResourceParser {
public:
ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
const ResourceParserOptions& options = {});
bool Parse(xml::XmlPullParser* parser);
@@ -110,7 +110,7 @@
IDiagnostics* diag_;
ResourceTable* table_;
Source source_;
- ConfigDescription config_;
+ android::ConfigDescription config_;
ResourceParserOptions options_;
};
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 41b4041..9de43c0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -29,6 +29,7 @@
using ::aapt::io::StringInputStream;
using ::aapt::test::StrValueEq;
using ::aapt::test::ValueEq;
+using ::android::ConfigDescription;
using ::android::Res_value;
using ::android::ResTable_map;
using ::android::StringPiece;
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index d0faac3..c2274d0 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -23,9 +23,9 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-#include "ConfigDescription.h"
#include "NameMangler.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
@@ -33,6 +33,7 @@
#include "util/Util.h"
using ::aapt::text::IsValidResourceEntryName;
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::base::StringPrintf;
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 8534eaa..7b19a31 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -17,7 +17,6 @@
#ifndef AAPT_RESOURCE_TABLE_H
#define AAPT_RESOURCE_TABLE_H
-#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "Resource.h"
#include "ResourceValues.h"
@@ -26,6 +25,7 @@
#include "io/File.h"
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include <functional>
@@ -66,7 +66,7 @@
class ResourceConfigValue {
public:
// The configuration for which this value is defined.
- const ConfigDescription config;
+ const android::ConfigDescription config;
// The product for which this value is defined.
const std::string product;
@@ -74,7 +74,7 @@
// The actual Value.
std::unique_ptr<Value> value;
- ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product)
+ ResourceConfigValue(const android::ConfigDescription& config, const android::StringPiece& product)
: config(config), product(product.to_string()) {}
private:
@@ -103,14 +103,14 @@
explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
- ResourceConfigValue* FindValue(const ConfigDescription& config);
+ ResourceConfigValue* FindValue(const android::ConfigDescription& config);
- ResourceConfigValue* FindValue(const ConfigDescription& config,
+ ResourceConfigValue* FindValue(const android::ConfigDescription& config,
const android::StringPiece& product);
- ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
+ ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
const android::StringPiece& product);
- std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config);
+ std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
template <typename Func>
std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
@@ -182,29 +182,30 @@
// When a collision of resources occurs, this method decides which value to keep.
static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
- bool AddResource(const ResourceNameRef& name, const ConfigDescription& config,
+ bool AddResource(const ResourceNameRef& name, const android::ConfigDescription& config,
const android::StringPiece& product, std::unique_ptr<Value> value,
IDiagnostics* diag);
bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
- const ConfigDescription& config, const android::StringPiece& product,
- std::unique_ptr<Value> value, IDiagnostics* diag);
+ const android::ConfigDescription& config,
+ const android::StringPiece& product, std::unique_ptr<Value> value,
+ IDiagnostics* diag);
- bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+ bool AddFileReference(const ResourceNameRef& name, const android::ConfigDescription& config,
const Source& source, const android::StringPiece& path, IDiagnostics* diag);
- bool AddFileReferenceMangled(const ResourceNameRef& name, const ConfigDescription& config,
+ bool AddFileReferenceMangled(const ResourceNameRef& name, const android::ConfigDescription& config,
const Source& source, const android::StringPiece& path,
io::IFile* file, IDiagnostics* diag);
// Same as AddResource, but doesn't verify the validity of the name. This is used
// when loading resources from an existing binary resource table that may have mangled names.
- bool AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config,
+ bool AddResourceMangled(const ResourceNameRef& name, const android::ConfigDescription& config,
const android::StringPiece& product, std::unique_ptr<Value> value,
IDiagnostics* diag);
bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
const android::StringPiece& product, std::unique_ptr<Value> value,
IDiagnostics* diag);
@@ -277,11 +278,12 @@
IDiagnostics* diag);
bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
- const ConfigDescription& config, const android::StringPiece& product,
- std::unique_ptr<Value> value, NameValidator name_validator,
- const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag);
+ const android::ConfigDescription& config,
+ const android::StringPiece& product, std::unique_ptr<Value> value,
+ NameValidator name_validator, const CollisionResolverFunc& conflict_resolver,
+ IDiagnostics* diag);
- bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config,
+ bool AddFileReferenceImpl(const ResourceNameRef& name, const android::ConfigDescription& config,
const Source& source, const android::StringPiece& path, io::IFile* file,
NameValidator name_validator, IDiagnostics* diag);
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 7fa8ea2..1a1f73f 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -24,6 +24,7 @@
#include <ostream>
#include <string>
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::testing::Eq;
using ::testing::NotNull;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 560077c..82d9e04 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -31,6 +31,7 @@
#include "util/Util.h"
using ::aapt::text::Utf8Iterator;
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::StringPiece16;
using ::android::base::StringPrintf;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 7af2fe0..e2f1c89 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,6 +20,7 @@
#include <functional>
#include <memory>
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
@@ -219,7 +220,8 @@
// Parses the binary form of a resource value. `type` is used as a hint to know when a value is
// an ID versus a False boolean value, etc. `config` is for sorting strings in the string pool.
-std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const ConfigDescription& config,
+std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type,
+ const android::ConfigDescription& config,
const android::ResStringPool& src_pool,
const android::Res_value& res_value,
StringPool* dst_pool);
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index f5b464d..1006ca9 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -24,9 +24,9 @@
#include <vector>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
-#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "util/BigBuffer.h"
@@ -60,12 +60,12 @@
kLowPriority = 0xffffffffu,
};
uint32_t priority = kNormalPriority;
- ConfigDescription config;
+ android::ConfigDescription config;
Context() = default;
- Context(uint32_t p, const ConfigDescription& c) : priority(p), config(c) {}
+ Context(uint32_t p, const android::ConfigDescription& c) : priority(p), config(c) {}
explicit Context(uint32_t p) : priority(p) {}
- explicit Context(const ConfigDescription& c) : priority(kNormalPriority), config(c) {
+ explicit Context(const android::ConfigDescription& c) : priority(kNormalPriority), config(c) {
}
};
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index ab8a4b7..411ad74 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -21,11 +21,11 @@
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/utf8.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "Flags.h"
#include "ResourceParser.h"
@@ -50,6 +50,7 @@
using ::aapt::io::FileInputStream;
using ::aapt::text::Printer;
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
using ::google::protobuf::io::CopyingOutputStreamAdaptor;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index db42e7c..60cab5d 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -24,13 +24,13 @@
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/stringprintf.h"
+#include "androidfw/Locale.h"
#include "androidfw/StringPiece.h"
#include "AppInfo.h"
#include "Debug.h"
#include "Flags.h"
#include "LoadedApk.h"
-#include "Locale.h"
#include "NameMangler.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
@@ -68,6 +68,7 @@
#include "xml/XmlDom.h"
using ::aapt::io::FileInputStream;
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::base::StringPrintf;
@@ -105,6 +106,7 @@
bool no_version_vectors = false;
bool no_version_transitions = false;
bool no_resource_deduping = false;
+ bool no_resource_removal = false;
bool no_xml_namespaces = false;
bool do_not_compress_anything = false;
std::unordered_set<std::string> extensions_to_not_compress;
@@ -1806,10 +1808,12 @@
// Before we process anything, remove the resources whose default values don't exist.
// We want to force any references to these to fail the build.
- if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "failed removing resources with no defaults");
- return 1;
+ if (!options_.no_resource_removal) {
+ if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed removing resources with no defaults");
+ return 1;
+ }
}
ReferenceLinker linker;
@@ -2084,6 +2088,10 @@
"Disables automatic deduping of resources with\n"
"identical values across compatible configurations.",
&options.no_resource_deduping)
+ .OptionalSwitch("--no-resource-removal",
+ "Disables automatic removal of resources without defaults. Use this only\n"
+ "when building runtime resource overlay packages.",
+ &options.no_resource_removal)
.OptionalSwitch("--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
"This decreases APK size at the cost of resource retrieval performance.",
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 9c76119..45297a7 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -20,6 +20,7 @@
#include "android-base/file.h"
#include "android-base/stringprintf.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
@@ -45,6 +46,7 @@
using ::aapt::configuration::Abi;
using ::aapt::configuration::OutputArtifact;
+using ::android::ConfigDescription;
using ::android::ResTable_config;
using ::android::StringPiece;
using ::android::base::ReadFileToString;
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 8b3a670..25010c5 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -19,15 +19,17 @@
#include <vector>
#include "android-base/logging.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/Locale.h"
-#include "ConfigDescription.h"
-#include "Locale.h"
#include "ResourceUtils.h"
#include "ValueVisitor.h"
#include "split/TableSplitter.h"
#include "util/Maybe.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
+using ::android::LocaleValue;
using ::android::StringPiece;
namespace aapt {
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 36c24bc..c5de9e0 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -24,6 +24,7 @@
#include "compile/Pseudolocalizer.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::StringPiece16;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
index 711558a..3135802 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -19,6 +19,8 @@
#include "test/Test.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
+
namespace aapt {
TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index 902334b..dd06b38 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -25,8 +25,8 @@
#include "android-base/file.h"
#include "android-base/logging.h"
+#include "androidfw/ConfigDescription.h"
-#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "ResourceUtils.h"
#include "configuration/ConfigurationParser.internal.h"
@@ -40,6 +40,8 @@
#include "xml/XmlDom.h"
#include "xml/XmlUtil.h"
+using ::android::ConfigDescription;
+
namespace aapt {
namespace {
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 7f1d445..b9e3be9 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -22,7 +22,8 @@
#include <unordered_map>
#include <vector>
-#include "ConfigDescription.h"
+#include "androidfw/ConfigDescription.h"
+
#include "Diagnostics.h"
#include "util/Maybe.h"
@@ -109,8 +110,8 @@
std::string name;
int version;
std::vector<Abi> abis;
- std::vector<ConfigDescription> screen_densities;
- std::vector<ConfigDescription> locales;
+ std::vector<android::ConfigDescription> screen_densities;
+ std::vector<android::ConfigDescription> locales;
Maybe<AndroidSdk> android_sdk;
std::vector<DeviceFeature> features;
std::vector<GlTexture> textures;
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index f071a69..c541688 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -17,6 +17,8 @@
#ifndef AAPT2_CONFIGURATIONPARSER_INTERNAL_H
#define AAPT2_CONFIGURATIONPARSER_INTERNAL_H
+#include "androidfw/ConfigDescription.h"
+
#include "configuration/ConfigurationParser.h"
#include <algorithm>
@@ -148,8 +150,8 @@
Maybe<std::string> artifact_format;
Group<Abi> abi_groups;
- Group<ConfigDescription> screen_density_groups;
- Group<ConfigDescription> locale_groups;
+ Group<android::ConfigDescription> screen_density_groups;
+ Group<android::ConfigDescription> locale_groups;
Group<DeviceFeature> device_feature_groups;
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index febbb2e..960880a 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -26,6 +26,8 @@
#include "test/Test.h"
#include "xml/XmlDom.h"
+using ::android::ConfigDescription;
+
namespace aapt {
namespace configuration {
diff --git a/tools/aapt2/filter/ConfigFilter.cpp b/tools/aapt2/filter/ConfigFilter.cpp
index 5fbe77e..9d10d59 100644
--- a/tools/aapt2/filter/ConfigFilter.cpp
+++ b/tools/aapt2/filter/ConfigFilter.cpp
@@ -16,9 +16,10 @@
#include "filter/ConfigFilter.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-#include "ConfigDescription.h"
+using ::android::ConfigDescription;
namespace aapt {
diff --git a/tools/aapt2/filter/ConfigFilter.h b/tools/aapt2/filter/ConfigFilter.h
index ebb8151..c4b7e43 100644
--- a/tools/aapt2/filter/ConfigFilter.h
+++ b/tools/aapt2/filter/ConfigFilter.h
@@ -20,7 +20,7 @@
#include <set>
#include <utility>
-#include "ConfigDescription.h"
+#include "androidfw/ConfigDescription.h"
namespace aapt {
@@ -34,7 +34,7 @@
/**
* Returns true if the filter matches the configuration, false otherwise.
*/
- virtual bool Match(const ConfigDescription& config) const = 0;
+ virtual bool Match(const android::ConfigDescription& config) const = 0;
};
/**
@@ -46,12 +46,12 @@
*/
class AxisConfigFilter : public IConfigFilter {
public:
- void AddConfig(ConfigDescription config);
+ void AddConfig(android::ConfigDescription config);
- bool Match(const ConfigDescription& config) const override;
+ bool Match(const android::ConfigDescription& config) const override;
private:
- std::set<std::pair<ConfigDescription, uint32_t>> configs_;
+ std::set<std::pair<android::ConfigDescription, uint32_t>> configs_;
uint32_t config_mask_ = 0;
};
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index a1f9f83..2bdc051 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -20,6 +20,7 @@
#include <string>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "ResourceTable.h"
@@ -54,22 +55,28 @@
bool ParseType(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
bool ParseLibrary(const android::ResChunk_header* chunk);
- std::unique_ptr<Item> ParseValue(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Item> ParseValue(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::Res_value& value);
- std::unique_ptr<Value> ParseMapEntry(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Value> ParseMapEntry(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Style> ParseStyle(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Style> ParseStyle(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Attribute> ParseAttr(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Attribute> ParseAttr(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Array> ParseArray(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Array> ParseArray(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Plural> ParsePlural(const ResourceNameRef& name, const ConfigDescription& config,
+ std::unique_ptr<Plural> ParsePlural(const ResourceNameRef& name,
+ const android::ConfigDescription& config,
const android::ResTable_map_entry* map);
/**
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 3b101b7..d1b2fdb 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -19,13 +19,15 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/Locale.h"
-#include "Locale.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+using ::android::ConfigDescription;
+using ::android::LocaleValue;
using ::android::ResStringPool;
namespace aapt {
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index 0c581a1..723a1c0 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -18,9 +18,9 @@
#define AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-#include "ConfigDescription.h"
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
@@ -34,14 +34,15 @@
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
StringPool* value_pool, io::IFileCollection* files,
std::string* out_error);
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
- const ConfigDescription& config, StringPool* value_pool,
- io::IFileCollection* files, std::string* out_error);
+ const android::ConfigDescription& config,
+ StringPool* value_pool, io::IFileCollection* files,
+ std::string* out_error);
std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
std::string* out_error);
@@ -49,8 +50,8 @@
bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
std::string* out_error);
-bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
- std::string* out_error);
+bool DeserializeConfigFromPb(const pb::Configuration& pb_config,
+ android::ConfigDescription* out_config, std::string* out_error);
// Optional io::IFileCollection used to lookup references to files in the ResourceTable.
bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 411cc29..7e35ea7 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -19,6 +19,8 @@
#include "ValueVisitor.h"
#include "util/BigBuffer.h"
+using android::ConfigDescription;
+
namespace aapt {
void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
index 951494c..c40e5dd 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -18,8 +18,8 @@
#define AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
-#include "ConfigDescription.h"
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
@@ -49,7 +49,7 @@
void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag);
// Serializes a ConfigDescription into its protobuf representation.
-void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config);
+void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config);
// Serializes a ResourceTable into its protobuf representation.
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, IDiagnostics* diag);
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 21fdbd8..a0d92f7 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -20,6 +20,7 @@
#include "format/proto/ProtoDeserialize.h"
#include "test/Test.h"
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::testing::Eq;
using ::testing::IsEmpty;
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index c0eaa8e..7872738 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -41,46 +41,46 @@
ASSERT_FALSE(in.HadError());
EXPECT_THAT(in.ByteCount(), Eq(0u));
- const char* buffer;
+ const void* buffer;
size_t size;
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError();
+ ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError();
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(in.ByteCount(), Eq(10u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("this is a "));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a "));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
in.BackUp(5u);
EXPECT_THAT(in.ByteCount(), Eq(15u));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(5u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin"));
// Backup 1 more than possible. Should clamp.
in.BackUp(11u);
EXPECT_THAT(in.ByteCount(), Eq(10u));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(20u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
- ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ ASSERT_TRUE(in.Next(&buffer, &size));
ASSERT_THAT(size, Eq(1u));
ASSERT_THAT(buffer, NotNull());
ASSERT_THAT(in.ByteCount(), Eq(21u));
- EXPECT_THAT(StringPiece(buffer, size), Eq("g"));
+ EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g"));
- EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+ EXPECT_FALSE(in.Next(&buffer, &size));
EXPECT_FALSE(in.HadError());
}
@@ -93,25 +93,25 @@
ASSERT_FALSE(out.HadError());
EXPECT_THAT(out.ByteCount(), Eq(0u));
- char* buffer;
+ void* buffer;
size_t size;
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(10u));
- memcpy(buffer, input.c_str(), size);
+ memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size);
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(20u));
- memcpy(buffer, input.c_str() + 10u, size);
+ memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size);
- ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+ ASSERT_TRUE(out.Next(&buffer, &size));
ASSERT_THAT(size, Eq(10u));
ASSERT_THAT(buffer, NotNull());
EXPECT_THAT(out.ByteCount(), Eq(30u));
- buffer[0] = input[20u];
+ reinterpret_cast<char*>(buffer)[0] = input[20u];
out.BackUp(size - 1);
EXPECT_THAT(out.ByteCount(), Eq(21u));
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index be67c9c..10e504e 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -26,21 +26,20 @@
#include "util/Maybe.h"
#include "xml/XmlDom.h"
-using ::android::StringPiece;
using ::aapt::text::IsJavaIdentifier;
namespace aapt {
-static Maybe<StringPiece> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
+static Maybe<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
const std::string& value) {
- StringPiece result = value;
+ std::string result = value;
size_t pos = value.rfind('.');
if (pos != std::string::npos) {
result = result.substr(pos + 1);
}
// Normalize only the java identifier, leave the original value unchanged.
- if (result.contains("-")) {
+ if (result.find("-") != std::string::npos) {
result = JavaClassGenerator::TransformToFieldName(result);
}
@@ -64,7 +63,7 @@
return false;
}
- Maybe<StringPiece> result =
+ Maybe<std::string> result =
ExtractJavaIdentifier(diag, source.WithLine(el->line_number), attr->value);
if (!result) {
return false;
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index 37d1a5f..f774e3a 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -21,6 +21,7 @@
#include "test/Test.h"
using ::aapt::io::StringOutputStream;
+using ::android::ConfigDescription;
using ::testing::HasSubstr;
using ::testing::Not;
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index f80c6e9..960c7d4 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -20,14 +20,16 @@
#include "android-base/logging.h"
-#include "ConfigDescription.h"
#include "ResourceTable.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+using android::ConfigDescription;
+
namespace aapt {
-bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
+bool ShouldGenerateVersionedResource(const ResourceEntry* entry,
+ const ConfigDescription& config,
const ApiVersion sdk_version_to_generate) {
// We assume the caller is trying to generate a version greater than the current configuration.
CHECK(sdk_version_to_generate > config.sdkVersion);
diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp
index 49639f8..1117472 100644
--- a/tools/aapt2/link/AutoVersioner_test.cpp
+++ b/tools/aapt2/link/AutoVersioner_test.cpp
@@ -16,9 +16,11 @@
#include "link/Linkers.h"
-#include "ConfigDescription.h"
+#include "androidfw/ConfigDescription.h"
+
#include "test/Test.h"
+using ::android::ConfigDescription;
using ::testing::NotNull;
namespace aapt {
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 3c9c476..c9b8d39 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -21,6 +21,7 @@
#include <unordered_set>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "Resource.h"
@@ -32,7 +33,6 @@
class ResourceTable;
class ResourceEntry;
-struct ConfigDescription;
// Defines the context in which a resource value is defined. Most resources are defined with the
// implicit package name of their compilation context. Understanding the package name of a resource
@@ -43,12 +43,14 @@
// Determines whether a versioned resource should be created. If a versioned resource already
// exists, it takes precedence.
-bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
+bool ShouldGenerateVersionedResource(const ResourceEntry* entry,
+ const android::ConfigDescription& config,
const ApiVersion sdk_version_to_generate);
// Finds the next largest ApiVersion of the config which is identical to the given config except
// for sdkVersion.
-ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry, const ConfigDescription& config);
+ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,
+ const android::ConfigDescription& config);
class AutoVersioner : public IResourceTableConsumer {
public:
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index ee4e702..7180a99 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -252,6 +252,7 @@
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.
@@ -346,6 +347,7 @@
manifest_action["uses-permission"];
manifest_action["uses-permission-sdk-23"];
manifest_action["permission"];
+ manifest_action["permission"]["meta-data"] = meta_data_action;
manifest_action["permission-tree"];
manifest_action["permission-group"];
manifest_action["uses-configuration"];
@@ -355,6 +357,8 @@
manifest_action["compatible-screens"];
manifest_action["compatible-screens"]["screen"];
manifest_action["supports-gl-texture"];
+ manifest_action["restrict-update"];
+ manifest_action["package-verifier"];
manifest_action["meta-data"] = meta_data_action;
manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
@@ -376,6 +380,7 @@
uses_static_library_action.Action(RequiredNameIsJavaPackage);
uses_static_library_action.Action(RequiredAndroidAttribute("version"));
uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
+ uses_static_library_action["additional-certificate"];
if (options_.debug_mode) {
application_action.Action([&](xml::Element* el) -> bool {
@@ -399,6 +404,8 @@
application_action["provider"]["grant-uri-permission"];
application_action["provider"]["path-permission"];
+ manifest_action["package"] = manifest_action;
+
return true;
}
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.cpp b/tools/aapt2/link/NoDefaultResourceRemover.cpp
index cfb4b26..13054bf 100644
--- a/tools/aapt2/link/NoDefaultResourceRemover.cpp
+++ b/tools/aapt2/link/NoDefaultResourceRemover.cpp
@@ -14,12 +14,16 @@
* limitations under the License.
*/
+#include "androidfw/Locale.h"
+
#include "link/NoDefaultResourceRemover.h"
#include <algorithm>
#include "ResourceTable.h"
+using android::ConfigDescription;
+
namespace aapt {
static bool IsDefaultConfigRequired(const ConfigDescription& config) {
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index 86dd56a..dd47674 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -18,6 +18,8 @@
#include "test/Test.h"
+using ::android::ConfigDescription;
+
namespace aapt {
TEST(ProductFilterTest, SelectTwoProducts) {
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 588b331..aa9f9ab 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -20,6 +20,7 @@
#include <regex>
#include <string>
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "LoadedApk.h"
@@ -43,6 +44,7 @@
using ::aapt::configuration::OutputArtifact;
using ::aapt::xml::kSchemaAndroid;
using ::aapt::xml::XmlResource;
+using ::android::ConfigDescription;
using ::android::StringPiece;
/**
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index c858879..4a5a6c3d 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -22,6 +22,8 @@
#include <unordered_set>
#include <vector>
+#include "androidfw/ConfigDescription.h"
+
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "configuration/ConfigurationParser.h"
@@ -66,7 +68,7 @@
/**
* Adds the <screen> elements to the parent node for the provided density configuration.
*/
- void AddScreens(const ConfigDescription& config, xml::Element* parent);
+ void AddScreens(const android::ConfigDescription& config, xml::Element* parent);
LoadedApk* apk_;
IAaptContext* context_;
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index 80eb737..7d87eb8 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -31,6 +31,8 @@
#include "test/Context.h"
#include "test/Test.h"
+using ::android::ConfigDescription;
+
namespace aapt {
namespace {
diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp
index 9d16268..ee2dfbc 100644
--- a/tools/aapt2/optimize/ResourceDeduper.cpp
+++ b/tools/aapt2/optimize/ResourceDeduper.cpp
@@ -21,6 +21,8 @@
#include "DominatorTree.h"
#include "ResourceTable.h"
+using android::ConfigDescription;
+
namespace aapt {
namespace {
diff --git a/tools/aapt2/optimize/ResourceDeduper_test.cpp b/tools/aapt2/optimize/ResourceDeduper_test.cpp
index d9f384c0..2e098ae 100644
--- a/tools/aapt2/optimize/ResourceDeduper_test.cpp
+++ b/tools/aapt2/optimize/ResourceDeduper_test.cpp
@@ -20,6 +20,7 @@
#include "test/Test.h"
using ::aapt::test::HasValue;
+using ::android::ConfigDescription;
using ::testing::Not;
namespace aapt {
diff --git a/tools/aapt2/optimize/VersionCollapser.cpp b/tools/aapt2/optimize/VersionCollapser.cpp
index cc1fc1e..f985604 100644
--- a/tools/aapt2/optimize/VersionCollapser.cpp
+++ b/tools/aapt2/optimize/VersionCollapser.cpp
@@ -21,6 +21,8 @@
#include "ResourceTable.h"
+using android::ConfigDescription;
+
namespace aapt {
template <typename Iterator, typename Pred>
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 70efbf5..a844a43 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -21,15 +21,16 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "androidfw/AssetManager.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-#include "ConfigDescription.h"
#include "NameMangler.h"
#include "Resource.h"
#include "ResourceUtils.h"
#include "ValueVisitor.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
using ::android::StringPiece;
using ::android::StringPiece16;
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index e991743..1dd5502 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -24,11 +24,13 @@
#include <vector>
#include "android-base/logging.h"
+#include "androidfw/ConfigDescription.h"
-#include "ConfigDescription.h"
#include "ResourceTable.h"
#include "util/Util.h"
+using ::android::ConfigDescription;
+
namespace aapt {
using ConfigClaimedMap = std::unordered_map<ResourceConfigValue*, bool>;
diff --git a/tools/aapt2/split/TableSplitter.h b/tools/aapt2/split/TableSplitter.h
index 6aec257..91afaa3 100644
--- a/tools/aapt2/split/TableSplitter.h
+++ b/tools/aapt2/split/TableSplitter.h
@@ -20,8 +20,8 @@
#include <set>
#include <vector>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
-#include "ConfigDescription.h"
#include "ResourceTable.h"
#include "filter/ConfigFilter.h"
#include "process/IResourceTableConsumer.h"
@@ -29,7 +29,7 @@
namespace aapt {
struct SplitConstraints {
- std::set<ConfigDescription> configs;
+ std::set<android::ConfigDescription> configs;
};
struct TableSplitterOptions {
diff --git a/tools/aapt2/split/TableSplitter_test.cpp b/tools/aapt2/split/TableSplitter_test.cpp
index d52f4b44..cdf0738 100644
--- a/tools/aapt2/split/TableSplitter_test.cpp
+++ b/tools/aapt2/split/TableSplitter_test.cpp
@@ -18,6 +18,8 @@
#include "test/Test.h"
+using ::android::ConfigDescription;
+
namespace aapt {
TEST(TableSplitterTest, NoSplitPreferredDensity) {
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index c4eab12..f33ae31 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -28,6 +28,7 @@
using ::aapt::configuration::ConfiguredArtifact;
using ::aapt::configuration::GetOrCreateGroup;
using ::aapt::io::StringInputStream;
+using ::android::ConfigDescription;
using ::android::StringPiece;
namespace aapt {
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index fd5262a..a88b11e 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -20,6 +20,7 @@
#include <memory>
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "Resource.h"
#include "ResourceTable.h"
@@ -40,7 +41,8 @@
ResourceTableBuilder& SetPackageId(const android::StringPiece& package_name, uint8_t id);
ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ResourceId& id = {});
- ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ConfigDescription& config,
+ ResourceTableBuilder& AddSimple(const android::StringPiece& name,
+ const android::ConfigDescription& config,
const ResourceId& id = {});
ResourceTableBuilder& AddReference(const android::StringPiece& name,
const android::StringPiece& ref);
@@ -51,7 +53,8 @@
ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
const android::StringPiece& str);
ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
- const ConfigDescription& config, const android::StringPiece& str);
+ const android::ConfigDescription& config,
+ const android::StringPiece& str);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
const android::StringPiece& path,
io::IFile* file = nullptr);
@@ -60,12 +63,13 @@
io::IFile* file = nullptr);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
const android::StringPiece& path,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
io::IFile* file = nullptr);
ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value);
ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
std::unique_ptr<Value> value);
- ResourceTableBuilder& AddValue(const android::StringPiece& name, const ConfigDescription& config,
+ ResourceTableBuilder& AddValue(const android::StringPiece& name,
+ const android::ConfigDescription& config,
const ResourceId& id, std::unique_ptr<Value> value);
ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
Visibility::Level level, bool allow_new = false);
@@ -163,8 +167,8 @@
ArtifactBuilder& SetName(const std::string& name);
ArtifactBuilder& SetVersion(int version);
ArtifactBuilder& AddAbi(configuration::Abi abi);
- ArtifactBuilder& AddDensity(const ConfigDescription& density);
- ArtifactBuilder& AddLocale(const ConfigDescription& locale);
+ ArtifactBuilder& AddDensity(const android::ConfigDescription& density);
+ ArtifactBuilder& AddLocale(const android::ConfigDescription& locale);
ArtifactBuilder& SetAndroidSdk(int min_sdk);
configuration::OutputArtifact Build();
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index 0fabbc4..b54c155 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -16,6 +16,8 @@
#include "test/Common.h"
+using android::ConfigDescription;
+
namespace aapt {
namespace test {
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index aca161a..50b41f1 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -21,11 +21,11 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "ConfigDescription.h"
#include "Debug.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
@@ -45,15 +45,15 @@
return ref.ToResourceName();
}
-inline ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
- ConfigDescription config;
- CHECK(ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
+inline android::ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
+ android::ConfigDescription config;
+ CHECK(android::ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
return config;
}
template <typename T = Value>
T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
const android::StringPiece& product) {
Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
if (result) {
@@ -68,12 +68,12 @@
template <>
Value* GetValueForConfigAndProduct<Value>(ResourceTable* table,
const android::StringPiece& res_name,
- const ConfigDescription& config,
+ const android::ConfigDescription& config,
const android::StringPiece& product);
template <typename T = Value>
T* GetValueForConfig(ResourceTable* table, const android::StringPiece& res_name,
- const ConfigDescription& config) {
+ const android::ConfigDescription& config) {
return GetValueForConfigAndProduct<T>(table, res_name, config, {});
}
diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h
index 3045255..d4b3abc 100644
--- a/tools/aapt2/util/BigBuffer.h
+++ b/tools/aapt2/util/BigBuffer.h
@@ -68,7 +68,7 @@
*/
explicit BigBuffer(size_t block_size);
- BigBuffer(BigBuffer&& rhs);
+ BigBuffer(BigBuffer&& rhs) noexcept;
/**
* Number of occupied bytes in all the allocated blocks.
@@ -136,7 +136,7 @@
inline BigBuffer::BigBuffer(size_t block_size)
: block_size_(block_size), size_(0) {}
-inline BigBuffer::BigBuffer(BigBuffer&& rhs)
+inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept
: block_size_(rhs.block_size_),
size_(rhs.size_),
blocks_(std::move(rhs.blocks_)) {}
diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h
index 59858e4..1727b18 100644
--- a/tools/aapt2/util/ImmutableMap.h
+++ b/tools/aapt2/util/ImmutableMap.h
@@ -32,8 +32,8 @@
using const_iterator =
typename std::vector<std::pair<TKey, TValue>>::const_iterator;
- ImmutableMap(ImmutableMap&&) = default;
- ImmutableMap& operator=(ImmutableMap&&) = default;
+ ImmutableMap(ImmutableMap&&) noexcept = default;
+ ImmutableMap& operator=(ImmutableMap&&) noexcept = default;
static ImmutableMap<TKey, TValue> CreatePreSorted(
std::initializer_list<std::pair<TKey, TValue>> list) {
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
index 9a82418..031276c 100644
--- a/tools/aapt2/util/Maybe.h
+++ b/tools/aapt2/util/Maybe.h
@@ -46,7 +46,7 @@
template <typename U>
Maybe(const Maybe<U>& rhs); // NOLINT(implicit)
- Maybe(Maybe&& rhs);
+ Maybe(Maybe&& rhs) noexcept;
template <typename U>
Maybe(Maybe<U>&& rhs); // NOLINT(implicit)
@@ -56,7 +56,7 @@
template <typename U>
Maybe& operator=(const Maybe<U>& rhs);
- Maybe& operator=(Maybe&& rhs);
+ Maybe& operator=(Maybe&& rhs) noexcept;
template <typename U>
Maybe& operator=(Maybe<U>&& rhs);
@@ -134,7 +134,7 @@
}
template <typename T>
-Maybe<T>::Maybe(Maybe&& rhs) : nothing_(rhs.nothing_) {
+Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) {
if (!rhs.nothing_) {
rhs.nothing_ = true;
@@ -192,7 +192,7 @@
}
template <typename T>
-inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
+inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept {
// Delegate to the actual assignment.
return move(std::forward<Maybe<T>>(rhs));
}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6c46e67..fdc800b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -212,8 +212,8 @@
move_from_files(args.input_greylists, uncategorized, light_greylist)
move_from_files(args.input_blacklists, uncategorized, blacklist)
- # Iterate over all uncategorized members and move serialization API to light greylist.
- move_serialization(uncategorized, light_greylist)
+ # Iterate over all uncategorized members and move serialization API to whitelist.
+ move_serialization(uncategorized, whitelist)
# Extract package names of members from whitelist and light greylist, which
# are assumed to have been finalized at this point. Assign all uncategorized
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 8f79318..4716241 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -85,5 +85,23 @@
self.assertEqual(
dst, set([ "Lfoo/bar/ClassA;->abc()J", "Lfoo/bar/ClassA;->def()J" ]))
+ def test_move_serialization(self):
+ # All the entries should be moved apart from the last one
+ src = set([ "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)V",
+ "Lfoo/bar/ClassA;->readObjectNoData()V",
+ "Lfoo/bar/ClassA;->readResolve()Ljava/lang/Object;",
+ "Lfoo/bar/ClassA;->serialVersionUID:J",
+ "Lfoo/bar/ClassA;->serialPersistentFields:[Ljava/io/ObjectStreamField;",
+ "Lfoo/bar/ClassA;->writeObject(Ljava/io/ObjectOutputStream;)V",
+ "Lfoo/bar/ClassA;->writeReplace()Ljava/lang/Object;",
+ # Should not be moved as signature does not match
+ "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)I"])
+ expectedToMove = len(src) - 1
+ dst = set()
+ packages = set([ "Lfoo/bar/" ])
+ move_serialization(src, dst)
+ self.assertEqual(len(src), 1)
+ self.assertEqual(len(dst), expectedToMove)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
new file mode 100755
index 0000000..48c0755
--- /dev/null
+++ b/tools/hiddenapi/merge_csv.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# 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.
+"""
+Merge mutliple CSV files, possibly with different columns, writing to stdout.
+"""
+
+import csv
+import sys
+
+csv_readers = [
+ csv.DictReader(open(csv_file, 'rb'), delimiter=',', quotechar='|')
+ for csv_file in sys.argv[1:]
+]
+
+# Build union of all columns from source files:
+headers = set()
+for reader in csv_readers:
+ headers = headers.union(reader.fieldnames)
+
+# Concatenate all files to output:
+out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', fieldnames = sorted(headers))
+out.writeheader()
+for reader in csv_readers:
+ for row in reader:
+ out.writerow(row)
+
+
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index bdcc807..710da40 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -12,8 +12,8 @@
# Sort
IFS=$'\n'
# Stash away comments
-C=( $(grep -E '^#' <<< "${A[*]}") )
-A=( $(grep -v -E '^#' <<< "${A[*]}") )
+C=( $(grep -E '^#' <<< "${A[*]}" || :) )
+A=( $(grep -v -E '^#' <<< "${A[*]}" || :) )
# Sort entries
A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
A=( $(uniq <<< "${A[*]}") )
@@ -21,4 +21,6 @@
A=( ${C[*]} ${A[*]} )
unset IFS
# Dump array back into the file
-printf '%s\n' "${A[@]}" > "$dest_list"
+if [ ${#A[@]} -ne 0 ]; then
+ printf '%s\n' "${A[@]}" > "$dest_list"
+fi
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 3689a8f..4b5677a 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -140,7 +140,7 @@
size_t base = 0;
size_t found;
while (true) {
- found = args.find_first_of(" ", base);
+ found = args.find_first_of(' ', base);
if (found != base) {
string arg = args.substr(base, found - base);
printf(" \"%s\",", arg.c_str());
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index 5c9df6a..c7993e3 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -189,8 +189,7 @@
Map<String, Long> homeNetworkIds = new HashMap<>();
byte[] rawSsidBytes = new byte[33];
Arrays.fill(rawSsidBytes, (byte) 'a');
- homeNetworkIds.put(
- StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ homeNetworkIds.put(new String(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
homeSp.setHomeNetworkIds(homeNetworkIds);
assertFalse(homeSp.validate());
}