summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp13
-rw-r--r--Android.mk255
-rwxr-xr-xapi/current.txt98
-rw-r--r--api/system-current.txt20
-rw-r--r--cmds/incidentd/src/Section.cpp28
-rw-r--r--cmds/screencap/screencap.cpp9
-rw-r--r--cmds/statsd/src/atoms.proto88
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp8
-rw-r--r--config/boot-image-profile.txt1
-rw-r--r--config/hiddenapi-light-greylist.txt105
-rw-r--r--config/preloaded-classes6
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/Notification.java66
-rw-r--r--core/java/android/app/backup/package.html2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java59
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java56
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java5
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java4
-rw-r--r--core/java/android/content/IntentFilter.java2
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java3
-rw-r--r--core/java/android/content/pm/PackageManager.java2
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java68
-rw-r--r--core/java/android/hardware/biometrics/BiometricAuthenticator.java25
-rw-r--r--core/java/android/hardware/face/FaceManager.java88
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java70
-rw-r--r--core/java/android/nfc/tech/MifareClassic.java2
-rw-r--r--core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java4
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/service/autofill/SaveInfo.java15
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java3
-rw-r--r--core/java/android/text/TextWatcher.java2
-rw-r--r--core/java/android/text/style/SuggestionSpan.java2
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/android/view/ViewRootImpl.java8
-rw-r--r--core/java/android/view/Window.java15
-rw-r--r--core/java/android/view/WindowManager.java1
-rw-r--r--core/java/android/view/WindowManagerGlobal.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java26
-rw-r--r--core/java/android/view/autofill/AutofillManager.java4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java6
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java4
-rw-r--r--core/java/android/widget/CursorAdapter.java2
-rw-r--r--core/java/android/widget/DatePickerSpinnerDelegate.java2
-rw-r--r--core/java/android/widget/Editor.java16
-rw-r--r--core/java/android/widget/NumberPicker.java6
-rw-r--r--core/java/android/widget/ShareActionProvider.java2
-rw-r--r--core/java/android/widget/TextView.java26
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java2
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java2
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java4
-rw-r--r--core/java/com/android/internal/os/KernelCpuProcReader.java58
-rw-r--r--core/java/com/android/internal/os/LooperStats.java25
-rw-r--r--core/res/res/drawable/ic_info.xml (renamed from packages/SettingsLib/res/drawable/ic_info.xml)2
-rw-r--r--core/res/res/values-mcc302-mnc370/strings.xml25
-rw-r--r--core/res/res/values-mcc302-mnc720/strings.xml25
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/dimens_material.xml3
-rw-r--r--core/res/res/values/public.xml13
-rw-r--r--core/res/res/values/strings.xml27
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java14
-rw-r--r--data/etc/platform.xml5
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/DeviceInfo.cpp60
-rw-r--r--libs/hwui/DeviceInfo.h35
-rw-r--r--libs/hwui/Extensions.h59
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp41
-rw-r--r--libs/hwui/debug/wrap_gles.h3
-rw-r--r--libs/hwui/pipeline/skia/DumpOpsCanvas.h8
-rw-r--r--libs/hwui/pipeline/skia/FunctorDrawable.h53
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp6
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.h18
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h6
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp15
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp223
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.h55
-rw-r--r--libs/hwui/renderthread/EglManager.cpp2
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp5
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp3
-rw-r--r--libs/hwui/tests/common/TestUtils.h18
-rw-r--r--libs/hwui/tests/unit/RenderPropertiesTests.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp7
-rw-r--r--libs/hwui/utils/Color.cpp20
-rw-r--r--libs/hwui/utils/Color.h3
-rw-r--r--libs/hwui/utils/GLUtils.cpp17
-rw-r--r--libs/hwui/utils/GLUtils.h51
-rw-r--r--media/java/android/media/MediaCodec.java15
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java150
-rw-r--r--media/jni/Android.bp3
-rw-r--r--media/jni/android_media_Media2HTTPConnection.cpp182
-rw-r--r--media/jni/android_media_Media2HTTPConnection.h58
-rw-r--r--media/jni/android_media_Media2HTTPService.cpp61
-rw-r--r--media/jni/android_media_Media2HTTPService.h45
-rw-r--r--media/jni/android_media_MediaCodec.cpp25
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp2
-rw-r--r--packages/PrintSpooler/res/layout/print_activity.xml1
-rw-r--r--packages/SettingsLib/HelpUtils/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/Android.bp1
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml (renamed from packages/SettingsLib/res/layout/restricted_icon.xml)7
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml25
-rw-r--r--packages/SettingsLib/res/layout/restricted_switch_widget.xml9
-rw-r--r--packages/SettingsLib/res/values/dimens.xml1
-rw-r--r--packages/SettingsLib/res/values/strings.xml5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java46
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java32
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java117
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java90
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java91
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java91
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java4
-rw-r--r--packages/SystemUI/res/layout/menu_ime.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java254
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java13
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java12
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java23
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationClient.java21
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java47
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java68
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java236
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java13
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java26
-rw-r--r--services/core/java/com/android/server/pm/ComponentResolver.java2
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java55
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java985
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java6
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java18
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java33
-rw-r--r--services/core/java/com/android/server/telecom/TelecomLoaderService.java137
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java13
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java44
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java150
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java8
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java185
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java8
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java22
-rwxr-xr-xstartop/scripts/app_startup/force_compiler_filter36
-rwxr-xr-xstartop/scripts/app_startup/launch_application6
-rwxr-xr-xstartop/scripts/app_startup/lib/common39
-rwxr-xr-xstartop/scripts/app_startup/run_app_with_prefetch17
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java22
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java19
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java27
-rw-r--r--telephony/java/com/android/internal/telephony/uicc/IccUtils.java32
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java15
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java86
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java15
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java67
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java (renamed from core/res/res/values-mcc262-mnc02/strings.xml)34
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/aapt2/LoadedApk.cpp2
-rw-r--r--tools/aapt2/LoadedApk.h2
-rw-r--r--tools/aapt2/cmd/Dump.cpp25
-rw-r--r--tools/aapt2/cmd/Dump.h3
-rw-r--r--tools/aapt2/cmd/Link.cpp6
-rw-r--r--tools/aapt2/cmd/Util.cpp12
-rw-r--r--tools/aapt2/cmd/Util_test.cpp287
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp2197
-rw-r--r--tools/aapt2/dump/DumpManifest.h61
-rw-r--r--tools/aapt2/split/TableSplitter.cpp6
-rw-r--r--tools/aapt2/split/TableSplitter.h1
-rw-r--r--tools/aapt2/test/Builders.h106
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java7
200 files changed, 6430 insertions, 2696 deletions
diff --git a/Android.bp b/Android.bp
index ca1c614e6c02..1c59e2b2cd03 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1166,7 +1166,7 @@ stubs_defaults {
previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
- "ojluni-annotated-stubs",
+ "ojluni-annotated-sdk-stubs",
],
}
@@ -1228,7 +1228,12 @@ stubs_defaults {
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",
],
}
@@ -1499,7 +1504,7 @@ droidstubs {
previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
- "ojluni-annotated-stubs",
+ "ojluni-annotated-sdk-stubs",
],
args: " --show-annotation android.annotation.SystemApi",
}
@@ -1585,6 +1590,7 @@ droidstubs {
removed_api_file: "api/removed.txt",
},
},
+ jdiff_enabled: true,
}
droidstubs {
@@ -1609,6 +1615,7 @@ droidstubs {
removed_api_file: "api/system-removed.txt",
},
},
+ jdiff_enabled: true,
}
droidstubs {
diff --git a/Android.mk b/Android.mk
index 5c4c2376f80e..d33307425968 100644
--- a/Android.mk
+++ b/Android.mk
@@ -53,265 +53,16 @@ $(gen): $(aidl_parcelables)
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
diff --git a/api/current.txt b/api/current.txt
index 1eecc2da673c..75787a7ad8e1 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -5581,14 +5581,14 @@ package android.app {
ctor public Notification.WearableExtender(android.app.Notification);
method public android.app.Notification.WearableExtender addAction(android.app.Notification.Action);
method public android.app.Notification.WearableExtender addActions(java.util.List<android.app.Notification.Action>);
- method public android.app.Notification.WearableExtender addPage(android.app.Notification);
- method public android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
+ method public deprecated android.app.Notification.WearableExtender addPage(android.app.Notification);
+ method public deprecated android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
method public android.app.Notification.WearableExtender clearActions();
- method public android.app.Notification.WearableExtender clearPages();
+ method public deprecated android.app.Notification.WearableExtender clearPages();
method public android.app.Notification.WearableExtender clone();
method public android.app.Notification.Builder extend(android.app.Notification.Builder);
method public java.util.List<android.app.Notification.Action> getActions();
- method public android.graphics.Bitmap getBackground();
+ method public deprecated android.graphics.Bitmap getBackground();
method public java.lang.String getBridgeTag();
method public int getContentAction();
method public deprecated int getContentIcon();
@@ -5597,17 +5597,17 @@ package android.app {
method public deprecated int getCustomContentHeight();
method public deprecated int getCustomSizePreset();
method public java.lang.String getDismissalId();
- method public android.app.PendingIntent getDisplayIntent();
+ method public deprecated android.app.PendingIntent getDisplayIntent();
method public deprecated int getGravity();
- method public boolean getHintAmbientBigPicture();
+ method public deprecated boolean getHintAmbientBigPicture();
method public deprecated boolean getHintAvoidBackgroundClipping();
method public boolean getHintContentIntentLaunchesActivity();
method public deprecated boolean getHintHideIcon();
method public deprecated int getHintScreenTimeout();
method public deprecated boolean getHintShowBackgroundOnly();
- method public java.util.List<android.app.Notification> getPages();
+ method public deprecated java.util.List<android.app.Notification> getPages();
method public boolean getStartScrollBottom();
- method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+ method public deprecated android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
method public android.app.Notification.WearableExtender setContentAction(int);
method public deprecated android.app.Notification.WearableExtender setContentIcon(int);
@@ -5616,23 +5616,23 @@ package android.app {
method public deprecated android.app.Notification.WearableExtender setCustomContentHeight(int);
method public deprecated android.app.Notification.WearableExtender setCustomSizePreset(int);
method public android.app.Notification.WearableExtender setDismissalId(java.lang.String);
- method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
+ method public deprecated android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public deprecated android.app.Notification.WearableExtender setGravity(int);
- method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
+ method public deprecated android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
method public deprecated android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
method public android.app.Notification.WearableExtender setHintContentIntentLaunchesActivity(boolean);
method public deprecated android.app.Notification.WearableExtender setHintHideIcon(boolean);
method public deprecated android.app.Notification.WearableExtender setHintScreenTimeout(int);
method public deprecated android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
- field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
- field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
- field public static final int SIZE_DEFAULT = 0; // 0x0
- field public static final int SIZE_FULL_SCREEN = 5; // 0x5
- field public static final int SIZE_LARGE = 4; // 0x4
- field public static final int SIZE_MEDIUM = 3; // 0x3
- field public static final int SIZE_SMALL = 2; // 0x2
- field public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final deprecated int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field public static final deprecated int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field public static final deprecated int SIZE_DEFAULT = 0; // 0x0
+ field public static final deprecated int SIZE_FULL_SCREEN = 5; // 0x5
+ field public static final deprecated int SIZE_LARGE = 4; // 0x4
+ field public static final deprecated int SIZE_MEDIUM = 3; // 0x3
+ field public static final deprecated int SIZE_SMALL = 2; // 0x2
+ field public static final deprecated int SIZE_XSMALL = 1; // 0x1
field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
}
@@ -7734,7 +7734,9 @@ package android.bluetooth {
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();
@@ -8102,7 +8104,9 @@ package android.bluetooth {
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();
@@ -8518,6 +8522,7 @@ package android.bluetooth {
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 {
@@ -18677,6 +18682,37 @@ package android.icu.text {
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();
@@ -19342,6 +19378,30 @@ package android.icu.text {
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);
@@ -49698,6 +49758,7 @@ package android.view.accessibility {
method public boolean isScrollable();
method public boolean isSelected();
method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
method public boolean isVisibleToUser();
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -49759,6 +49820,7 @@ package android.view.accessibility {
method public void setSource(android.view.View);
method public void setSource(android.view.View, int);
method public void setText(java.lang.CharSequence);
+ method public void setTextEntryKey(boolean);
method public void setTextSelection(int, int);
method public void setTooltipText(java.lang.CharSequence);
method public void setTraversalAfter(android.view.View);
diff --git a/api/system-current.txt b/api/system-current.txt
index 79bbace4734f..47b4cfc166f7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -219,6 +219,14 @@ package android {
field public static final int config_sendPackageName = 17891328; // 0x1110000
}
+ public static final class R.dimen {
+ field public static final int config_restricted_icon_size = 17104903; // 0x1050007
+ }
+
+ public static final class R.drawable {
+ field public static final int ic_info = 17301684; // 0x10800b4
+ }
+
public static final class R.raw {
field public static final int loaderror = 17825792; // 0x1100000
field public static final int nodomain = 17825793; // 0x1100001
@@ -357,11 +365,6 @@ package android.app {
field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
}
- public final class AutomaticZenRule implements android.os.Parcelable {
- ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long);
- ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long, android.service.notification.ZenPolicy);
- }
-
public class BroadcastOptions {
method public static android.app.BroadcastOptions makeBasic();
method public void setDontSendToRestrictedApps(boolean);
@@ -1115,6 +1118,7 @@ package android.content.pm {
public class PackageItemInfo {
method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
+ method public static void setForceSafeLabels(boolean);
field public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
field public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
field public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
@@ -4195,6 +4199,7 @@ package android.permissionpresenterservice {
method public final void attachBaseContext(android.content.Context);
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+ method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
}
@@ -6590,6 +6595,10 @@ package android.util {
package android.view {
+ public abstract class Window {
+ method public void addPrivateFlags(int);
+ }
+
public abstract interface WindowManager implements android.view.ViewManager {
method public abstract android.graphics.Region getCurrentImeTouchRegion();
}
@@ -6597,6 +6606,7 @@ package android.view {
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
method public final long getUserActivityTimeout();
method public final void setUserActivityTimeout(long);
+ field public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
}
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 87799b38906c..cd48af95d08a 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -407,7 +407,19 @@ WorkerThreadSection::WorkerThreadSection(int id, const int64_t timeoutMs, bool u
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());
@@ -486,6 +498,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
}
}
}
+
write_section_stats(requests->sectionStats(this->id), buffer);
if (timedOut || buffer.timedOut()) {
ALOGW("[%s] timed out", this->name.string());
@@ -773,7 +786,10 @@ status_t LogSection::BlockingCall(int pipeWriteFd) const {
}
}
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;
}
@@ -875,7 +891,7 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
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());
@@ -894,7 +910,13 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
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/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index b11e84322dde..e14f2eb41816 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -207,7 +207,14 @@ int main(int argc, char** argv)
result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
- if (base == NULL) {
+ if (base == nullptr || result != NO_ERROR) {
+ String8 reason;
+ if (base == nullptr) {
+ reason = "Failed to write to buffer";
+ } else {
+ reason.appendFormat("Error Code: %d", result);
+ }
+ fprintf(stderr, "Failed to take screenshot (%s)\n", reason.c_str());
close(fd);
return 1;
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 47387494a84b..13ae41df63f1 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -133,6 +133,9 @@ message Atom {
VibratorStateChanged vibrator_state_changed = 84;
DeferredJobStatsReported deferred_job_stats_reported = 85;
ThermalThrottlingStateChanged thermal_throttling = 86;
+ FingerprintAcquired fingerprint_acquired = 87;
+ FingerprintAuthenticated fingerprint_authenticated = 88;
+ FingerprintErrorOccurred fingerprint_error_occurred = 89;
}
// Pulled events will start at field 10000.
@@ -169,6 +172,7 @@ message Atom {
CategorySize category_size = 10028;
android.service.procstats.ProcessStatsSectionProto proc_stats = 10029;
BatteryVoltage battery_voltage = 10030;
+ NumFingerprints num_fingerprints = 10031;
}
// DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -432,9 +436,9 @@ message BleScanStateChanged {
* 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;
@@ -1832,6 +1836,60 @@ message GenericAtom {
optional android.os.statsd.EventType event_id = 2;
}
+/**
+ * Logs when a fingerprint acquire event occurs.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintAcquired {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // If this acquire is for a crypto fingerprint.
+ // e.g. Secure purchases, unlock password storage.
+ optional bool is_crypto = 2;
+}
+
+/**
+ * Logs when a fingerprint authentication event occurs.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintAuthenticated {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // If this authentication is for a crypto fingerprint.
+ // e.g. Secure purchases, unlock password storage.
+ optional bool is_crypto = 2;
+ // Whether or not this authentication was successful.
+ optional bool is_authenticated = 3;
+}
+
+/**
+ * Logs when a fingerprint error occurs.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintErrorOccurred {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // If this error is for a crypto fingerprint.
+ // e.g. Secure purchases, unlock password storage.
+ optional bool is_crypto = 2;
+
+ enum Error {
+ UNKNOWN = 0;
+ LOCKOUT = 1;
+ PERMANENT_LOCKOUT = 2;
+ }
+ // The type of error.
+ optional Error error = 3;
+}
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
@@ -2272,6 +2330,14 @@ message BinderCallsExceptions {
optional int64 exception_count = 2;
}
+/**
+ * Pulls the statistics of message dispatching on HandlerThreads.
+ *
+ * Looper stats will be reset every time the data is pulled. It means it can only be pulled by one
+ * config on the device.
+ *
+ * Next tag: 11
+ */
message LooperStats {
// Currently not collected and always set to 0.
optional int32 uid = 1 [(is_uid) = true];
@@ -2315,8 +2381,11 @@ message LooperStats {
// Total CPU usage of all processed message.
// Average can be computed using recorded_total_cpu_micros /
// recorded_message_count. Total can be computed using
- // recorded_total_cpu_micros / recorded_message_count * call_count.
+ // recorded_total_cpu_micros / recorded_message_count * message_count.
optional int64 recorded_total_cpu_micros = 9;
+
+ // True if the screen was interactive PowerManager#isInteractive at the end of the call.
+ optional bool screen_interactive = 10;
}
/**
@@ -2397,3 +2466,16 @@ message CategorySize {
// Uses System.currentTimeMillis(), which is wall clock time.
optional int64 cache_time_millis = 3;
}
+
+/**
+ * Pulls the number of fingerprints for each user.
+ *
+ * Pulled from StatsCompanionService, which queries FingerprintManager.
+ */
+message NumFingerprints {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // Number of fingerprints registered to that user.
+ optional int32 num_fingerprints = 2;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1cd13303619f..c23d65e2d146 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -190,7 +190,7 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// looper_stats
{android::util::LOOPER_STATS,
{{5, 6, 7, 8, 9},
- {2, 3, 4},
+ {2, 3, 4, 10},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
// Disk Stats
@@ -217,6 +217,12 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
+ // Number of fingerprints registered to each user.
+ {android::util::NUM_FINGERPRINTS,
+ {{},
+ {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index b683138a38de..be9ccec7ec86 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -11067,6 +11067,7 @@ HPLjava/lang/Long;->formatUnsignedLong(JI[CII)I
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 8c347fc7e169..04724616420b 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -2134,6 +2134,7 @@ Lcom/android/internal/telephony/IWapPushManager;->updatePackage(Ljava/lang/Strin
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
@@ -2226,6 +2227,7 @@ 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/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2247,6 +2249,108 @@ Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>()V
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
@@ -2553,6 +2657,7 @@ Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
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
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 50e97c53fe83..63c583f9264c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1436,6 +1436,12 @@ android.hardware.usb.UsbDevice$1
android.hardware.usb.UsbDeviceConnection
android.hardware.usb.UsbManager
android.hardware.usb.UsbRequest
+android.hidl.base.V1_0.DebugInfo
+android.hidl.base.V1_0.IBase
+android.hidl.manager.V1_0.IServiceManager
+android.hidl.manager.V1_0.IServiceManager$Proxy
+android.hidl.manager.V1_0.IServiceNotification
+android.hidl.manager.V1_0.IServiceNotification$Stub
android.icu.impl.BMPSet
android.icu.impl.CacheBase
android.icu.impl.CacheValue
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5499d59fe0b3..2ee266de4c77 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -545,12 +545,12 @@ import java.util.List;
* <a name="SavingPersistentState"></a>
* <h3>Saving Persistent State</h3>
*
- * <p>There are generally two kinds of persistent state than an activity
+ * <p>There are generally two kinds of persistent state that an activity
* will deal with: shared document-like data (typically stored in a SQLite
* database using a {@linkplain android.content.ContentProvider content provider})
* and internal state such as user preferences.</p>
*
- * <p>For content provider data, we suggest that activities use a
+ * <p>For content provider data, we suggest that activities use an
* "edit in place" user model. That is, any edits a user makes are effectively
* made immediately without requiring an additional confirmation step.
* Supporting this model is generally a simple matter of following two rules:</p>
@@ -1383,6 +1383,7 @@ public class Activity extends ContextThemeWrapper
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume(this, isTopOfTask());
+ enableAutofillCompatibilityIfNeeded();
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
View focus = getCurrentFocus();
@@ -7165,7 +7166,6 @@ public class Activity extends ContextThemeWrapper
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
- enableAutofillCompatibilityIfNeeded();
}
private void enableAutofillCompatibilityIfNeeded() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 217225e90f78..3638bc48d2b5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8253,7 +8253,10 @@ public class Notification implements Parcelable
* <p>For custom display notifications created using {@link #setDisplayIntent},
* the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based
* on their content.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_DEFAULT = 0;
/**
@@ -8261,7 +8264,10 @@ public class Notification implements Parcelable
* with an extra small size.
* <p>This value is only applicable for custom display notifications created using
* {@link #setDisplayIntent}.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_XSMALL = 1;
/**
@@ -8269,7 +8275,10 @@ public class Notification implements Parcelable
* with a small size.
* <p>This value is only applicable for custom display notifications created using
* {@link #setDisplayIntent}.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_SMALL = 2;
/**
@@ -8277,7 +8286,10 @@ public class Notification implements Parcelable
* with a medium size.
* <p>This value is only applicable for custom display notifications created using
* {@link #setDisplayIntent}.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_MEDIUM = 3;
/**
@@ -8285,7 +8297,10 @@ public class Notification implements Parcelable
* with a large size.
* <p>This value is only applicable for custom display notifications created using
* {@link #setDisplayIntent}.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_LARGE = 4;
/**
@@ -8293,20 +8308,29 @@ public class Notification implements Parcelable
* full screen.
* <p>This value is only applicable for custom display notifications created using
* {@link #setDisplayIntent}.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public static final int SIZE_FULL_SCREEN = 5;
/**
* Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
* short amount of time when this notification is displayed on the screen. This
* is the default value.
+ *
+ * @deprecated This feature is no longer supported.
*/
+ @Deprecated
public static final int SCREEN_TIMEOUT_SHORT = 0;
/**
* Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
* for a longer amount of time when this notification is displayed on the screen.
+ *
+ * @deprecated This feature is no longer supported.
*/
+ @Deprecated
public static final int SCREEN_TIMEOUT_LONG = -1;
/** Notification extra which contains wearable extensions */
@@ -8556,7 +8580,9 @@ public class Notification implements Parcelable
* @param intent the {@link PendingIntent} for an activity
* @return this object for method chaining
* @see android.app.Notification.WearableExtender#getDisplayIntent
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public WearableExtender setDisplayIntent(PendingIntent intent) {
mDisplayIntent = intent;
return this;
@@ -8565,7 +8591,10 @@ public class Notification implements Parcelable
/**
* Get the intent to launch inside of an activity view when displaying this
* notification. This {@code PendingIntent} should be for an activity.
+ *
+ * @deprecated Display intents are no longer supported.
*/
+ @Deprecated
public PendingIntent getDisplayIntent() {
return mDisplayIntent;
}
@@ -8579,7 +8608,9 @@ public class Notification implements Parcelable
* @param page the notification to add as another page
* @return this object for method chaining
* @see android.app.Notification.WearableExtender#getPages
+ * @deprecated Multiple content pages are no longer supported.
*/
+ @Deprecated
public WearableExtender addPage(Notification page) {
mPages.add(page);
return this;
@@ -8594,7 +8625,9 @@ public class Notification implements Parcelable
* @param pages a list of notifications
* @return this object for method chaining
* @see android.app.Notification.WearableExtender#getPages
+ * @deprecated Multiple content pages are no longer supported.
*/
+ @Deprecated
public WearableExtender addPages(List<Notification> pages) {
mPages.addAll(pages);
return this;
@@ -8604,7 +8637,9 @@ public class Notification implements Parcelable
* Clear all additional pages present on this builder.
* @return this object for method chaining.
* @see #addPage
+ * @deprecated Multiple content pages are no longer supported.
*/
+ @Deprecated
public WearableExtender clearPages() {
mPages.clear();
return this;
@@ -8616,7 +8651,9 @@ public class Notification implements Parcelable
* subsequent pages. This field can be used to separate a notification into multiple
* sections.
* @return the pages for this notification
+ * @deprecated Multiple content pages are no longer supported.
*/
+ @Deprecated
public List<Notification> getPages() {
return mPages;
}
@@ -8629,7 +8666,9 @@ public class Notification implements Parcelable
* @param background the background bitmap
* @return this object for method chaining
* @see android.app.Notification.WearableExtender#getBackground
+ * @deprecated Background images are no longer supported.
*/
+ @Deprecated
public WearableExtender setBackground(Bitmap background) {
mBackground = background;
return this;
@@ -8642,7 +8681,9 @@ public class Notification implements Parcelable
*
* @return the background image
* @see android.app.Notification.WearableExtender#setBackground
+ * @deprecated Background images are no longer supported.
*/
+ @Deprecated
public Bitmap getBackground() {
return mBackground;
}
@@ -8688,15 +8729,11 @@ public class Notification implements Parcelable
}
/**
- * Set an action from this notification's actions to be clickable with the content of
- * this notification. This action will no longer display separately from the
- * notification's content.
- *
- * <p>For notifications with multiple pages, child pages can also have content actions
- * set, although the list of available actions comes from the main notification and not
- * from the child page's notification.
+ * Set an action from this notification's actions as the primary action. If the action has a
+ * {@link RemoteInput} associated with it, shortcuts to the options for that input are shown
+ * directly on the notification.
*
- * @param actionIndex The index of the action to hoist onto the current notification page.
+ * @param actionIndex The index of the primary action.
* If wearable actions were added to the main notification, this index
* will apply to that list, otherwise it will apply to the regular
* actions list.
@@ -8707,13 +8744,8 @@ public class Notification implements Parcelable
}
/**
- * Get the index of the notification action, if any, that was specified as being clickable
- * with the content of this notification. This action will no longer display separately
- * from the notification's content.
- *
- * <p>For notifications with multiple pages, child pages can also have content actions
- * set, although the list of available actions comes from the main notification and not
- * from the child page's notification.
+ * Get the index of the notification action, if any, that was specified as the primary
+ * action.
*
* <p>If wearable specific actions were added to the main notification, this index will
* apply to that list, otherwise it will apply to the regular actions list.
@@ -8938,7 +8970,9 @@ public class Notification implements Parcelable
* qr codes, as well as other simple black-and-white tickets.
* @param hintAmbientBigPicture {@code true} to enable converstion and ambient.
* @return this object for method chaining
+ * @deprecated This feature is no longer supported.
*/
+ @Deprecated
public WearableExtender setHintAmbientBigPicture(boolean hintAmbientBigPicture) {
setFlag(FLAG_BIG_PICTURE_AMBIENT, hintAmbientBigPicture);
return this;
@@ -8950,7 +8984,9 @@ public class Notification implements Parcelable
* qr codes, as well as other simple black-and-white tickets.
* @return {@code true} if it should be displayed in ambient, false otherwise
* otherwise. The default value is {@code false} if this was never set.
+ * @deprecated This feature is no longer supported.
*/
+ @Deprecated
public boolean getHintAmbientBigPicture() {
return (mFlags & FLAG_BIG_PICTURE_AMBIENT) != 0;
}
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index 8b5e3ba3532f..dd6c2546898c 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -11,7 +11,7 @@ href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> guide.</p>
<p>All backup and restore operations are controlled by the {@link
android.app.backup.BackupManager}. Each application that would
-like to enable backup and preserve its data on remote strage must implement a
+like to enable backup and preserve its data on remote storage must implement a
backup agent. A backup agent can be built by extending either {@link android.app.backup.BackupAgent}
or {@link android.app.backup.BackupAgentHelper}. The {@link
android.app.backup.BackupAgentHelper} class provides a wrapper around {@link
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4c655b5ac027..654bfaf293b8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -81,7 +81,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* {@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 @@ public final class BluetoothAdapter {
/**
* 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 @@ public final class BluetoothAdapter {
* 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 @@ public final class BluetoothAdapter {
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 @@ public final class BluetoothAdapter {
}
/**
+ * 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 @@ public final class BluetoothAdapter {
* 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 @@ public final class BluetoothAdapter {
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 818a749842f7..73e98cd99f8f 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1963,8 +1963,8 @@ public final class BluetoothDevice implements Parcelable {
/**
* 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 +1975,71 @@ public final class BluetoothDevice implements Parcelable {
* 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
- * @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
+ public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
- Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled");
+ Log.e(TAG, "createInsecureL2capChannel: 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);
+ 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 {
+ Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
+ return createInsecureL2capChannel(psm);
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index ba4b5a566799..5fc344a14f99 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,12 +203,11 @@ public final class BluetoothServerSocket implements Closeable {
/**
* 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 780f896139f9..3a1e2f58c99d 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -667,6 +667,10 @@ public final class BluetoothSocket implements Closeable {
* @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/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 0dd618657004..0469a9006b25 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -125,7 +125,7 @@ import java.util.Set;
*
* <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/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 0c70a3d9509d..963f881e36d9 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -22,7 +22,6 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -104,7 +103,7 @@ public class PackageItemInfo {
private static volatile boolean sForceSafeLabels = false;
/** {@hide} */
- @UnsupportedAppUsage
+ @SystemApi
public static void setForceSafeLabels(boolean forceSafeLabels) {
sForceSafeLabels = forceSafeLabels;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1b4878c5e89f..a15711f5da50 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1979,6 +1979,8 @@ public abstract class PackageManager {
* </ul>
* A version of 1.1.0 or higher also indicates:
* <ul>
+ * <li>The {@code VK_ANDROID_external_memory_android_hardware_buffer} extension is
+ * supported.</li>
* <li>{@code SYNC_FD} external semaphore and fence handles are supported.</li>
* <li>{@code VkPhysicalDeviceSamplerYcbcrConversionFeatures::samplerYcbcrConversion} is
* supported.</li>
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index b5b4432bbdb2..20e1454e6276 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -136,6 +136,24 @@ public abstract class PackageManagerInternal {
public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
/**
+ * Sets the SMS packages provider.
+ * @param provider The packages provider.
+ */
+ public abstract void setSmsAppPackagesProvider(PackagesProvider provider);
+
+ /**
+ * Sets the dialer packages provider.
+ * @param provider The packages provider.
+ */
+ public abstract void setDialerAppPackagesProvider(PackagesProvider provider);
+
+ /**
+ * Sets the sim call manager packages provider.
+ * @param provider The packages provider.
+ */
+ public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
+
+ /**
* Sets the Use Open Wifi packages provider.
* @param provider The packages provider.
*/
@@ -148,28 +166,26 @@ public abstract class PackageManagerInternal {
public abstract void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider);
/**
- * Called when the package for the default dialer changed
- *
- * @param packageName the new dialer package
- * @param userId user for which the change was made
+ * Requests granting of the default permissions to the current default SMS app.
+ * @param packageName The default SMS package name.
+ * @param userId The user for which to grant the permissions.
*/
- public void onDefaultDialerAppChanged(String packageName, int userId) {}
+ public abstract void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId);
/**
- * Called when the package for the default SMS handler changed
- *
- * @param packageName the new sms package
- * @param userId user for which the change was made
+ * Requests granting of the default permissions to the current default dialer app.
+ * @param packageName The default dialer package name.
+ * @param userId The user for which to grant the permissions.
*/
- public void onDefaultSmsAppChanged(String packageName, int userId) {}
+ public abstract void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId);
/**
- * Called when the package for the default sim call manager changed
- *
- * @param packageName the new sms package
- * @param userId user for which the change was made
+ * Requests granting of the default permissions to the current default sim call manager.
+ * @param packageName The default sim call manager package name.
+ * @param userId The user for which to grant the permissions.
*/
- public void onDefaultSimCallManagerAppChanged(String packageName, int userId) {}
+ public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName,
+ int userId);
/**
* Requests granting of the default permissions to the current default Use Open Wifi app.
@@ -430,8 +446,8 @@ public abstract class PackageManagerInternal {
*
* @param packageName The package to check for
* @param uid the uid in which the package is running
- * @return {@link #USER_TRUSTED} if the user has trusted the package, {@link #USER_BLOCKED}
- * if user has blocked requests from the package, {@link #USER_DEFAULT} if the user response
+ * @return {@link USER_TRUSTED} if the user has trusted the package, {@link USER_BLOCKED}
+ * if user has blocked requests from the package, {@link USER_DEFAULT} if the user response
* is not yet available
*/
int getPackageTrustedToInstallApps(String packageName, int uid);
@@ -545,7 +561,7 @@ public abstract class PackageManagerInternal {
/**
* Returns a list without a change observer.
*
- * @see #getPackageList(PackageListObserver)
+ * {@see #getPackageList(PackageListObserver)}
*/
public @NonNull PackageList getPackageList() {
return getPackageList(null);
@@ -574,16 +590,7 @@ public abstract class PackageManagerInternal {
/**
* Returns a package object for the disabled system package name.
*/
- public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
- @NonNull String packageName);
-
- /**
- * Returns the package name for the disabled system package.
- *
- * This is equivalent to
- * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
- */
- public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
+ public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName);
/**
* Returns whether or not the component is the resolver activity.
@@ -612,7 +619,7 @@ public abstract class PackageManagerInternal {
* Access may be limited based upon whether the calling or target applications
* are instant applications.
*
- * @see #canAccessInstantApps
+ * @see #canAccessInstantApps(int)
*/
public abstract boolean filterAppAccess(
@Nullable PackageParser.Package pkg, int callingUid, int userId);
@@ -628,9 +635,6 @@ public abstract class PackageManagerInternal {
public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
@NonNull String packageName, int flagMask, int flagValues, int userId);
- /** Returns whether the given package was signed by the platform */
- public abstract boolean isPlatformSigned(String pkg);
-
/**
* Returns true if it's still safe to restore data backed up from this app's version
* that was signed with restoringFromSigHash.
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index dbb25276dd97..c604ff167636 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -202,31 +202,6 @@ public interface BiometricAuthenticator {
}
/**
- * @param error
- * @param vendorCode
- * @return the error string associated with this error
- */
- default String getErrorString(int error, int vendorCode) {
- throw new UnsupportedOperationException("Stub!");
- }
-
- /**
- * @param acquireInfo
- * @param vendorCode
- * @return the help string associated with this code
- */
- default String getAcquiredString(int acquireInfo, int vendorCode) {
- throw new UnsupportedOperationException("Stub!");
- }
-
- /**
- * @return one of {@link #TYPE_FINGERPRINT} {@link #TYPE_IRIS} or {@link #TYPE_FACE}
- */
- default int getType() {
- throw new UnsupportedOperationException("Stub!");
- }
-
- /**
* This call warms up the hardware and starts scanning for valid biometrics. It terminates
* when {@link AuthenticationCallback#onAuthenticationError(int,
* CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 0f83c8bb5e67..20e0116a0473 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -168,10 +168,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
} catch (RemoteException e) {
Log.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
- // Though this may not be a hardware issue, it will cause apps to give up or try
- // again later.
+ // Though this may not be a hardware issue, it will cause apps to give up or
+ // try again later.
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
- getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -232,10 +233,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in enroll: ", e);
if (callback != null) {
- // Though this may not be a hardware issue, it will cause apps to give up or try
- // again later.
+ // Though this may not be a hardware issue, it will cause apps to give up or
+ // try again later.
callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
- getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -315,7 +317,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
Log.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
- getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -513,32 +516,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
}
- @Override
- public String getErrorString(int errMsg, int vendorCode) {
+ /**
+ * @hide
+ */
+ public static String getErrorString(Context context, int errMsg, int vendorCode) {
switch (errMsg) {
case FACE_ERROR_HW_UNAVAILABLE:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.face_error_hw_not_available);
case FACE_ERROR_UNABLE_TO_PROCESS:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.face_error_unable_to_process);
case FACE_ERROR_TIMEOUT:
- return mContext.getString(com.android.internal.R.string.face_error_timeout);
+ return context.getString(com.android.internal.R.string.face_error_timeout);
case FACE_ERROR_NO_SPACE:
- return mContext.getString(com.android.internal.R.string.face_error_no_space);
+ return context.getString(com.android.internal.R.string.face_error_no_space);
case FACE_ERROR_CANCELED:
- return mContext.getString(com.android.internal.R.string.face_error_canceled);
+ return context.getString(com.android.internal.R.string.face_error_canceled);
case FACE_ERROR_LOCKOUT:
- return mContext.getString(com.android.internal.R.string.face_error_lockout);
+ return context.getString(com.android.internal.R.string.face_error_lockout);
case FACE_ERROR_LOCKOUT_PERMANENT:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.face_error_lockout_permanent);
case FACE_ERROR_NOT_ENROLLED:
- return mContext.getString(com.android.internal.R.string.face_error_not_enrolled);
+ return context.getString(com.android.internal.R.string.face_error_not_enrolled);
case FACE_ERROR_HW_NOT_PRESENT:
- return mContext.getString(com.android.internal.R.string.face_error_hw_not_present);
+ return context.getString(com.android.internal.R.string.face_error_hw_not_present);
case FACE_ERROR_VENDOR: {
- String[] msgArray = mContext.getResources().getStringArray(
+ String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.face_error_vendor);
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
@@ -552,35 +557,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
/**
* @hide
*/
- @Override
- public String getAcquiredString(int acquireInfo, int vendorCode) {
+ public static String getAcquiredString(Context context, int acquireInfo, int vendorCode) {
switch (acquireInfo) {
case FACE_ACQUIRED_GOOD:
return null;
case FACE_ACQUIRED_INSUFFICIENT:
- return mContext.getString(R.string.face_acquired_insufficient);
+ return context.getString(R.string.face_acquired_insufficient);
case FACE_ACQUIRED_TOO_BRIGHT:
- return mContext.getString(R.string.face_acquired_too_bright);
+ return context.getString(R.string.face_acquired_too_bright);
case FACE_ACQUIRED_TOO_DARK:
- return mContext.getString(R.string.face_acquired_too_dark);
+ return context.getString(R.string.face_acquired_too_dark);
case FACE_ACQUIRED_TOO_CLOSE:
- return mContext.getString(R.string.face_acquired_too_close);
+ return context.getString(R.string.face_acquired_too_close);
case FACE_ACQUIRED_TOO_FAR:
- return mContext.getString(R.string.face_acquired_too_far);
+ return context.getString(R.string.face_acquired_too_far);
case FACE_ACQUIRED_TOO_HIGH:
- return mContext.getString(R.string.face_acquired_too_high);
+ return context.getString(R.string.face_acquired_too_high);
case FACE_ACQUIRED_TOO_LOW:
- return mContext.getString(R.string.face_acquired_too_low);
+ return context.getString(R.string.face_acquired_too_low);
case FACE_ACQUIRED_TOO_RIGHT:
- return mContext.getString(R.string.face_acquired_too_right);
+ return context.getString(R.string.face_acquired_too_right);
case FACE_ACQUIRED_TOO_LEFT:
- return mContext.getString(R.string.face_acquired_too_left);
+ return context.getString(R.string.face_acquired_too_left);
case FACE_ACQUIRED_POOR_GAZE:
- return mContext.getString(R.string.face_acquired_poor_gaze);
+ return context.getString(R.string.face_acquired_poor_gaze);
case FACE_ACQUIRED_NOT_DETECTED:
- return mContext.getString(R.string.face_acquired_not_detected);
+ return context.getString(R.string.face_acquired_not_detected);
case FACE_ACQUIRED_VENDOR: {
- String[] msgArray = mContext.getResources().getStringArray(
+ String[] msgArray = context.getResources().getStringArray(
R.array.face_acquired_vendor);
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
@@ -592,18 +596,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
- * @hide
- */
- @Override
- public int getType() {
- return TYPE_FACE;
- }
-
- /**
* Used so BiometricPrompt can map the face ones onto existing public constants.
* @hide
*/
- public int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
+ public static int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
switch (acquireInfo) {
case FACE_ACQUIRED_GOOD:
return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
@@ -898,13 +894,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
? (vendorCode + FACE_ERROR_VENDOR_BASE) : errMsgId;
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
} else if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
} else if (mRemovalCallback != null) {
mRemovalCallback.onRemovalError(mRemovalFace, clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
}
}
@@ -932,7 +928,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
}
- final String msg = getAcquiredString(acquireInfo, vendorCode);
+ final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
if (msg == null) {
return;
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b380a2e08c8a..a4f3ce1b9cce 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -426,7 +426,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
- getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -476,7 +477,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
- getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -546,7 +548,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
Slog.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
- getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -568,7 +571,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
Slog.w(TAG, "Remote exception in enumerate: ", e);
if (callback != null) {
callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
- getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+ getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
}
}
}
@@ -862,7 +866,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
}
- final String msg = getAcquiredString(acquireInfo, vendorCode);
+ final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
if (msg == null) {
return;
}
@@ -882,16 +886,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
} else if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
} else if (mRemovalCallback != null) {
mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
} else if (mEnumerateCallback != null) {
mEnumerateCallback.onEnumerateError(clientErrMsgId,
- getErrorString(errMsgId, vendorCode));
+ getErrorString(mContext, errMsgId, vendorCode));
}
}
@@ -934,38 +938,37 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* @hide
*/
- @Override
- public String getErrorString(int errMsg, int vendorCode) {
+ public static String getErrorString(Context context, int errMsg, int vendorCode) {
switch (errMsg) {
case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_unable_to_process);
case FINGERPRINT_ERROR_HW_UNAVAILABLE:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_hw_not_available);
case FINGERPRINT_ERROR_NO_SPACE:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_no_space);
case FINGERPRINT_ERROR_TIMEOUT:
- return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
+ return context.getString(com.android.internal.R.string.fingerprint_error_timeout);
case FINGERPRINT_ERROR_CANCELED:
- return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
+ return context.getString(com.android.internal.R.string.fingerprint_error_canceled);
case FINGERPRINT_ERROR_LOCKOUT:
- return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
+ return context.getString(com.android.internal.R.string.fingerprint_error_lockout);
case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_lockout_permanent);
case FINGERPRINT_ERROR_USER_CANCELED:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_user_canceled);
case FINGERPRINT_ERROR_NO_FINGERPRINTS:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_no_fingerprints);
case FINGERPRINT_ERROR_HW_NOT_PRESENT:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_error_hw_not_present);
case FINGERPRINT_ERROR_VENDOR: {
- String[] msgArray = mContext.getResources().getStringArray(
+ String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
@@ -979,28 +982,27 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* @hide
*/
- @Override
- public String getAcquiredString(int acquireInfo, int vendorCode) {
+ public static String getAcquiredString(Context context, int acquireInfo, int vendorCode) {
switch (acquireInfo) {
case FINGERPRINT_ACQUIRED_GOOD:
return null;
case FINGERPRINT_ACQUIRED_PARTIAL:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_acquired_partial);
case FINGERPRINT_ACQUIRED_INSUFFICIENT:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_acquired_insufficient);
case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_acquired_imager_dirty);
case FINGERPRINT_ACQUIRED_TOO_SLOW:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_acquired_too_slow);
case FINGERPRINT_ACQUIRED_TOO_FAST:
- return mContext.getString(
+ return context.getString(
com.android.internal.R.string.fingerprint_acquired_too_fast);
case FINGERPRINT_ACQUIRED_VENDOR: {
- String[] msgArray = mContext.getResources().getStringArray(
+ String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
if (vendorCode < msgArray.length) {
return msgArray[vendorCode];
@@ -1011,14 +1013,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return null;
}
- /**
- * @hide
- */
- @Override
- public int getType() {
- return TYPE_FINGERPRINT;
- }
-
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@Override // binder call
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index 02819a667c39..080e058737b6 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -38,7 +38,7 @@ import java.nio.ByteOrder;
* <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks.
* <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks.
* <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks.
- * <li>MIFARE Classic 4k} are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks
+ * <li>MIFARE Classic 4k are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks
* and the last 8 sectors contain 16 blocks.
* </ul>
*
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index e0bffaeb9d3e..f2da21e818f5 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -17,7 +17,6 @@
package android.permissionpresenterservice;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -78,10 +77,7 @@ public abstract class RuntimePermissionPresenterService extends Service {
*
* @param packageName The package for which to revoke
* @param permissionName The permission to revoke
- *
- * @hide
*/
- @UnsupportedAppUsage
public abstract void onRevokeRuntimePermission(String packageName, String permissionName);
@Override
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4c7f0f3d823d..aa178fb9ff36 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11537,14 +11537,6 @@ public final class Settings {
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/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index f5719568c1ad..dfaf49ad6a03 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -235,12 +235,17 @@ public final class SaveInfo implements Parcelable {
*/
public static final int FLAG_DONT_SAVE_ON_FINISH = 0x2;
+
/**
- * Don't trigger the autofill save UI when the autofill context associated with the response
- * associated with this {@link SaveInfo} is {@link AutofillManager#commit() committed},
- * but keep its {@link FillContext} so it's delivered in a future
- * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) save request} of an
- * activity belonging to the same task.
+ * Postpone the autofill save UI.
+ *
+ * <p>If flag is set, the autofill save UI is not triggered when the
+ * autofill context associated with the response associated with this {@link SaveInfo} is
+ * committed (with {@link AutofillManager#commit()}). Instead, the {@link FillContext}
+ * is delivered in future fill requests (with {@link
+ * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)})
+ * and save request (with {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)})
+ * of an activity belonging to the same task.
*
* <p>This flag should be used when the service detects that the application uses
* multiple screens to implement an autofillable workflow (for example, one screen for the
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 26240c572898..c1a3c2b5f150 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -283,6 +283,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
throw ex.rethrowFromSystemServer();
+ } catch (SecurityException e) {
+ // app cannot catch and recover from this, so do on their behalf
+ Log.w(TAG, "Enqueue adjustment failed; no longer connected", e);
}
}
break;
diff --git a/core/java/android/text/TextWatcher.java b/core/java/android/text/TextWatcher.java
index bad09f2a0f0e..a0aef690a1b8 100644
--- a/core/java/android/text/TextWatcher.java
+++ b/core/java/android/text/TextWatcher.java
@@ -17,7 +17,7 @@
package android.text;
/**
- * When an object of a type is attached to an Editable, its methods will
+ * When an object of this type is attached to an Editable, its methods will
* be called when the text is changed.
*/
public interface TextWatcher extends NoCopySpan {
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 521044778257..be47320b59bd 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -420,7 +420,7 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, hashCode());
context.sendBroadcast(intent);
} else {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = context.getSystemService(InputMethodManager.class);
if (imm != null) {
imm.notifySuggestionPicked(this, original, index);
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index ff6e86ebff61..183e83304925 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -35,6 +35,7 @@ public class FeatureFlagUtils {
public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
+ public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -47,6 +48,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
+ DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "false");
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c29fbbb2125f..19e3f7f623cb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7315,7 +7315,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Here we check whether we still need the default focus highlight, and switch it on/off.
switchDefaultFocusHighlight();
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (!gainFocus) {
if (isPressed()) {
setPressed(false);
@@ -8523,6 +8523,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
|| importance == IMPORTANT_FOR_AUTOFILL_NO) {
+ if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) {
+ Log.v(AUTOFILL_LOG_TAG, "View (autofillId=" + getAutofillViewId() + ", "
+ + getClass() + ") is not important for autofill because its "
+ + "importance is " + importance);
+ }
return false;
}
@@ -12476,7 +12481,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
onFinishTemporaryDetach();
if (hasWindowFocus() && hasFocus()) {
- InputMethodManager.getInstance().focusIn(this);
+ getContext().getSystemService(InputMethodManager.class).focusIn(this);
}
notifyEnterOrExitForAutoFillIfNeeded(true);
}
@@ -12867,7 +12872,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* focus, false otherwise.
*/
public void onWindowFocusChanged(boolean hasWindowFocus) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (!hasWindowFocus) {
if (isPressed()) {
setPressed(false);
@@ -17932,7 +17937,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
rebuildOutline();
if (isFocused()) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
imm.focusIn(this);
}
@@ -18515,7 +18520,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
onDetachedFromWindow();
onDetachedFromWindowInternal();
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
imm.onViewDetachedFromWindow(this);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 16d202b8af1d..2ee7ab939bd9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2579,7 +2579,7 @@ public final class ViewRootImpl implements ViewParent,
.mayUseInputMethod(mWindowAttributes.flags);
if (imTarget != mLastWasImTarget) {
mLastWasImTarget = imTarget;
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null && imTarget) {
imm.onPreWindowFocus(mView, hasWindowFocus);
imm.onPostWindowFocus(mView, mView.findFocus(),
@@ -2695,7 +2695,7 @@ public final class ViewRootImpl implements ViewParent,
mLastWasImTarget = WindowManager.LayoutParams
.mayUseInputMethod(mWindowAttributes.flags);
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
imm.onPreWindowFocus(mView, hasWindowFocus);
}
@@ -4329,7 +4329,7 @@ public final class ViewRootImpl implements ViewParent,
enqueueInputEvent(event, null, 0, true);
} break;
case MSG_CHECK_FOCUS: {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null) {
imm.checkFocus();
}
@@ -4871,7 +4871,7 @@ public final class ViewRootImpl implements ViewParent,
@Override
protected int onProcess(QueuedInputEvent q) {
if (mLastWasImTarget && !isInLocalFocusMode()) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null) {
final InputEvent event = q.mEvent;
if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a7ec6df00017..982737aedc74 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -25,6 +25,7 @@ import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StyleRes;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.WindowConfiguration;
import android.content.Context;
@@ -1079,8 +1080,18 @@ public abstract class Window {
setFlags(flags, flags);
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Add private flag bits.
+ *
+ * <p>Refer to the individual flags for the permissions needed.
+ *
+ * <p>Note: Only for updateable system components (aka. mainline modules)
+ *
+ * @param flags The flag bits to add.
+ *
+ * @hide
+ */
+ @SystemApi
public void addPrivateFlags(int flags) {
setPrivateFlags(flags, flags);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0404df027a4c..742df5e8a962 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1668,6 +1668,7 @@ public interface WindowManager extends ViewManager {
* this window is visible.
* @hide
*/
+ @SystemApi
@RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 4ca9a141fd23..e20acf1a0008 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -468,7 +468,7 @@ public final class WindowManagerGlobal {
View view = root.getView();
if (view != null) {
- InputMethodManager imm = InputMethodManager.getInstance();
+ InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
imm.windowDismissed(mViews.get(index).getWindowToken());
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a3fa2ceba4d3..4d3f0fc20ecd 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -632,6 +632,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x0200000;
+ private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x0400000;
+
/**
* Bits that provide the id of a virtual descendant of a view.
*/
@@ -2461,6 +2463,30 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Returns whether node represents a text entry key that is part of a keyboard or keypad.
+ *
+ * @return {@code true} if the node is a text entry key., {@code false} otherwise.
+ */
+ public boolean isTextEntryKey() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY);
+ }
+
+ /**
+ * Sets whether the node represents a text entry key that is part of a keyboard or keypad.
+ *
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise.
+ */
+ public void setTextEntryKey(boolean isTextEntryKey) {
+ setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey);
+ }
+
+ /**
* Gets the package this node comes from.
*
* @return The package name.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9419e93d0066..e87048e1a5cb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -45,6 +45,7 @@ import android.service.autofill.UserData;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.KeyEvent;
@@ -559,6 +560,9 @@ public final class AutofillManager {
// different bridge based on which activity is currently focused
// in the current process. Since compat would be rarely used, just
// create and register a new instance every time.
+ if (sDebug) {
+ Slog.d(TAG, "creating CompatibilityBridge for " + mContext);
+ }
mCompatibilityBridge = new CompatibilityBridge();
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index cbaf72449b43..2f677f976e33 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -661,10 +661,12 @@ public final class InputMethodManager {
}
/**
- * Private optimization: retrieve the global InputMethodManager instance,
- * if it exists.
+ * Private optimization: retrieve the global InputMethodManager instance, if it exists.
* @hide
+ * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
+ * support multi-display scenario.
*/
+ @Deprecated
@UnsupportedAppUsage
public static InputMethodManager peekInstance() {
return sInstance;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index cbd624eec7d6..7d6564fd91fb 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1158,7 +1158,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Closes the drop down if present on screen.</p>
*/
public void dismissDropDown() {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
imm.displayCompletions(this, null);
}
@@ -1247,7 +1247,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
private void buildImeCompletions() {
final ListAdapter adapter = mAdapter;
if (adapter != null) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
final int count = Math.min(adapter.getCount(), 20);
CompletionInfo[] completions = new CompletionInfo[count];
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index cc8b55009316..e250f63bbc65 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -365,7 +365,7 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable,
* closed.
*
* @param newCursor The new cursor to be used.
- * @return Returns the previously set Cursor, or null if there wasa not one.
+ * @return Returns the previously set Cursor, or null if there was not one.
* If the given new Cursor is the same instance is the previously set
* Cursor, null is also returned.
*/
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index f88a4e2b414f..5f151105622e 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -639,7 +639,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
// changed the value via the IME and there is a next input the IME will
// be shown, otherwise the user chose another means of changing the
// value and having the IME up makes no sense.
- InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+ InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
if (inputMethodManager != null) {
if (inputMethodManager.isActive(mYearSpinnerInput)) {
mYearSpinnerInput.clearFocus();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 442859878598..8dd30f6abe24 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1539,6 +1539,10 @@ public class Editor {
}
}
+ private InputMethodManager getInputMethodManager() {
+ return mTextView.getContext().getSystemService(InputMethodManager.class);
+ }
+
public void beginBatchEdit() {
mInBatchEditControllers = true;
final InputMethodState ims = mInputMethodState;
@@ -1707,7 +1711,7 @@ public class Editor {
if (req == null) {
return false;
}
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
if (imm == null) {
return false;
}
@@ -1742,7 +1746,7 @@ public class Editor {
private void sendUpdateSelection() {
if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) {
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
if (null != imm) {
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
@@ -1768,7 +1772,7 @@ public class Editor {
final InputMethodState ims = mInputMethodState;
if (ims != null && ims.mBatchEditNesting == 0) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null) {
if (imm.isActive(mTextView)) {
if (ims.mContentChanged || ims.mSelectionModeChanged) {
@@ -2245,7 +2249,7 @@ public class Editor {
&& mTextView.isTextEditable() && !mTextView.isTextSelectable()
&& mShowSoftInputOnFocus) {
// Show the IME to be able to replace text, except when selecting non editable text.
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
if (imm != null) {
imm.showSoftInput(mTextView, 0, null);
}
@@ -2255,7 +2259,7 @@ public class Editor {
private boolean extractedTextModeWillBeStarted() {
if (!(mTextView.isInExtractedMode())) {
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
return imm != null && imm.isFullscreenMode();
}
return false;
@@ -4272,7 +4276,7 @@ public class Editor {
if (ims == null || ims.mBatchEditNesting > 0) {
return;
}
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
if (null == imm) {
return;
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index b6ed22c293f6..a28cc403ed56 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1293,7 +1293,8 @@ public class NumberPicker extends LinearLayout {
* Shows the soft input for its input text.
*/
private void showSoftInput() {
- InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+ InputMethodManager inputMethodManager =
+ getContext().getSystemService(InputMethodManager.class);
if (inputMethodManager != null) {
if (mHasSelectorWheel) {
mInputText.setVisibility(View.VISIBLE);
@@ -1307,7 +1308,8 @@ public class NumberPicker extends LinearLayout {
* Hides the soft input if it is active for the input text.
*/
private void hideSoftInput() {
- InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+ InputMethodManager inputMethodManager =
+ getContext().getSystemService(InputMethodManager.class);
if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 9a24061ba0d6..c78f4ac116ee 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -268,7 +268,7 @@ public class ShareActionProvider extends ActionProvider {
* Intent shareIntent = new Intent(Intent.ACTION_SEND);
* shareIntent.setType("image/*");
* Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
- * shareIntent.putExtra(Intent.EXTRA_STREAM, uri));</pre>
+ * shareIntent.putExtra(Intent.EXTRA_STREAM, uri);</pre>
*
* @param shareIntent The share intent.
*
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a86e6f81f006..dfbaf9ac0901 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2156,7 +2156,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!enabled) {
// Hide the soft input if the currently active TextView is disabled
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
@@ -2166,7 +2166,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (enabled) {
// Make sure IME is updated with current editor info.
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null) imm.restartInput(this);
}
@@ -2392,7 +2392,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
}
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null) imm.restartInput(this);
}
@@ -5769,7 +5769,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Editable t = mEditableFactory.newEditable(text);
text = t;
setFilters(t, mFilters);
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null) imm.restartInput(this);
} else if (precomputed != null) {
if (mTextDir == null) {
@@ -6148,7 +6148,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setTextInternal(removeSuggestionSpans(mText));
}
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null) imm.restartInput(this);
}
@@ -6436,7 +6436,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
} else if (actionCode == EditorInfo.IME_ACTION_DONE) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
@@ -7902,7 +7902,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!hasOnClickListeners()) {
if (mMovement != null && mText instanceof Editable
&& mLayout != null && onCheckIsTextEditor()) {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
viewClicked(imm);
if (imm != null && getShowSoftInputOnFocus()) {
imm.showSoftInput(this, 0);
@@ -7956,7 +7956,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
& KeyEvent.FLAG_EDITOR_ACTION) != 0) {
// No target for next focus, but make sure the IME
// if this came from it.
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
@@ -10260,7 +10260,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
// Show the IME, except when selecting in read-only text.
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
viewClicked(imm);
if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
imm.showSoftInput(this, 0);
@@ -11299,7 +11299,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Show the IME, except when selecting in read-only text.
if ((mMovement != null || onCheckIsTextEditor()) && hasSpannableText() && mLayout != null
&& (isTextEditable() || isTextSelectable()) && isFocused()) {
- final InputMethodManager imm = InputMethodManager.peekInstance();
+ final InputMethodManager imm = getInputMethodManager();
viewClicked(imm);
if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
handled |= imm.showSoftInput(this, 0);
@@ -11367,13 +11367,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
sendAccessibilityEventUnchecked(event);
}
+ private InputMethodManager getInputMethodManager() {
+ return getContext().getSystemService(InputMethodManager.class);
+ }
+
/**
* Returns whether this text view is a current input method target. The
* default implementation just checks with {@link InputMethodManager}.
* @return True if the TextView is a current input method target; false otherwise.
*/
public boolean isInputMethodTarget() {
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = getInputMethodManager();
return imm != null && imm.isActive(this);
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 77670b35a1ea..6a3a8f0821d8 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -269,7 +269,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
mRadialTimePickerModeButton.setContentDescription(
mTextInputPickerModeEnabledDescription);
updateTextInputPicker();
- InputMethodManager imm = InputMethodManager.peekInstance();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null) {
imm.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index cc79b9c85784..83c86d5ce36b 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -471,7 +471,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
// changed the value via the IME and there is a next input the IME will
// be shown, otherwise the user chose another means of changing the
// value and having the IME up makes no sense.
- InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+ InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
if (inputMethodManager != null) {
if (inputMethodManager.isActive(mHourSpinnerInput)) {
mHourSpinnerInput.clearFocus();
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index b33a5c4ffb7d..81dab2f6aeef 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -232,6 +232,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
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);
@@ -241,7 +242,6 @@ public abstract class FileSystemProvider extends DocumentsProvider {
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/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d0795c95a8ad..31f13c33c167 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5758,8 +5758,6 @@ public class BatteryStatsImpl extends BatteryStats {
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();
@@ -5768,8 +5766,6 @@ public class BatteryStatsImpl extends BatteryStats {
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/KernelCpuProcReader.java b/core/java/com/android/internal/os/KernelCpuProcReader.java
index 396deb4d7a0a..c233ea8e78b7 100644
--- a/core/java/com/android/internal/os/KernelCpuProcReader.java
+++ b/core/java/com/android/internal/os/KernelCpuProcReader.java
@@ -24,13 +24,14 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
+import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
/**
* Reads cpu time proc files with throttling (adjustable interval).
@@ -55,7 +56,6 @@ public class KernelCpuProcReader {
private static final int ERROR_THRESHOLD = 5;
// Throttle interval in milliseconds
private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
- private static final int INITIAL_BUFFER_SIZE = 8 * 1024;
private static final int MAX_BUFFER_SIZE = 1024 * 1024;
private static final String PROC_UID_FREQ_TIME = "/proc/uid_cpupower/time_in_state";
private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_cpupower/concurrent_active_time";
@@ -84,13 +84,12 @@ public class KernelCpuProcReader {
private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
private long mLastReadTime = Long.MIN_VALUE;
private final Path mProc;
- private ByteBuffer mBuffer;
+ private byte[] mBuffer = new byte[8 * 1024];
+ private int mContentSize;
@VisibleForTesting
public KernelCpuProcReader(String procFile) {
mProc = Paths.get(procFile);
- mBuffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
- mBuffer.clear();
}
/**
@@ -108,38 +107,45 @@ public class KernelCpuProcReader {
return null;
}
if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
- if (mBuffer.limit() > 0 && mBuffer.limit() < mBuffer.capacity()) {
- // mBuffer has data.
- return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+ if (mContentSize > 0) {
+ return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+ .order(ByteOrder.nativeOrder());
}
return null;
}
mLastReadTime = SystemClock.elapsedRealtime();
- mBuffer.clear();
+ mContentSize = 0;
final int oldMask = StrictMode.allowThreadDiskReadsMask();
- try (FileChannel fc = FileChannel.open(mProc, StandardOpenOption.READ)) {
- while (fc.read(mBuffer) == mBuffer.capacity()) {
- if (!resize()) {
- mErrors++;
- Slog.e(TAG, "Proc file is too large: " + mProc);
- return null;
+ try (InputStream in = Files.newInputStream(mProc)) {
+ int numBytes = 0;
+ int curr;
+ while ((curr = in.read(mBuffer, numBytes, mBuffer.length - numBytes)) >= 0) {
+ numBytes += curr;
+ if (numBytes == mBuffer.length) {
+ // Hit the limit. Resize mBuffer.
+ if (mBuffer.length == MAX_BUFFER_SIZE) {
+ mErrors++;
+ Slog.e(TAG, "Proc file is too large: " + mProc);
+ return null;
+ }
+ mBuffer = Arrays.copyOf(mBuffer,
+ Math.min(mBuffer.length << 1, MAX_BUFFER_SIZE));
}
- fc.position(0);
}
+ mContentSize = numBytes;
+ return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+ .order(ByteOrder.nativeOrder());
} catch (NoSuchFileException | FileNotFoundException e) {
// Happens when the kernel does not provide this file. Not a big issue. Just log it.
mErrors++;
Slog.w(TAG, "File not exist: " + mProc);
- return null;
} catch (IOException e) {
mErrors++;
Slog.e(TAG, "Error reading: " + mProc, e);
- return null;
} finally {
StrictMode.setThreadPolicyMask(oldMask);
}
- mBuffer.flip();
- return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+ return null;
}
/**
@@ -153,14 +159,4 @@ public class KernelCpuProcReader {
mThrottleInterval = throttleInterval;
}
}
-
- private boolean resize() {
- if (mBuffer.capacity() >= MAX_BUFFER_SIZE) {
- return false;
- }
- int newSize = Math.min(mBuffer.capacity() << 1, MAX_BUFFER_SIZE);
- // Slog.i(TAG, "Resize buffer " + mBuffer.capacity() + " => " + newSize);
- mBuffer = ByteBuffer.allocateDirect(newSize);
- return true;
- }
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 02a8b224e3c2..0650d0af7caf 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -106,6 +106,7 @@ public class LooperStats implements Looper.Observer {
synchronized (entry) {
entry.exceptionCount++;
}
+
recycleSession(session);
}
@@ -116,29 +117,29 @@ public class LooperStats implements Looper.Observer {
/** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */
public List<ExportedEntry> getEntries() {
- final ArrayList<ExportedEntry> entries;
+ final ArrayList<ExportedEntry> exportedEntries;
synchronized (mLock) {
final int size = mEntries.size();
- entries = new ArrayList<>(size);
+ exportedEntries = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
Entry entry = mEntries.valueAt(i);
synchronized (entry) {
- entries.add(new ExportedEntry(entry));
+ exportedEntries.add(new ExportedEntry(entry));
}
}
}
// Add the overflow and collision entries only if they have any data.
- if (mOverflowEntry.messageCount > 0 || mOverflowEntry.exceptionCount > 0) {
- synchronized (mOverflowEntry) {
- entries.add(new ExportedEntry(mOverflowEntry));
- }
- }
- if (mHashCollisionEntry.messageCount > 0 || mHashCollisionEntry.exceptionCount > 0) {
- synchronized (mHashCollisionEntry) {
- entries.add(new ExportedEntry(mHashCollisionEntry));
+ maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
+ maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
+ return exportedEntries;
+ }
+
+ private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) {
+ synchronized (specialEntry) {
+ if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) {
+ exportedEntries.add(new ExportedEntry(specialEntry));
}
}
- return entries;
}
/** Removes all collected data. */
diff --git a/packages/SettingsLib/res/drawable/ic_info.xml b/core/res/res/drawable/ic_info.xml
index afe7e6b782ca..f14c4b4f251a 100644
--- a/packages/SettingsLib/res/drawable/ic_info.xml
+++ b/core/res/res/drawable/ic_info.xml
@@ -18,7 +18,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?android:attr/colorAccent">
+ android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
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 f5b8496f9a0b..000000000000
--- 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 f5b8496f9a0b..000000000000
--- 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 293d90e276b3..1404383bc234 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -913,7 +913,7 @@
<!-- Control whether to lock day/night mode change from normal application. When it is
true, day / night mode change is only allowed to apps with MODIFY_DAY_NIGHT_MODE
permission. -->
- <bool name="config_lockDayNightMode">true</bool>
+ <bool name="config_lockDayNightMode">false</bool>
<!-- Control the default night mode to use when there is no other mode override set.
One of the following values (see UiModeManager.java):
@@ -3486,6 +3486,9 @@
<!-- Name of the font family used for system surfaces where the font should use medium weight -->
<string name="config_headlineFontFamilyMedium">@string/font_family_button_material</string>
+ <!-- Size of icon shown beside a preference locked by admin -->
+ <dimen name="config_restricted_icon_size">@dimen/restricted_icon_size_material</dimen>
+
<string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
<!-- Package name that should be granted Notification Assistant access -->
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 210f30eeb902..a0b40edd68a1 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -117,6 +117,9 @@
<!-- Default rounded corner for controls -->
<dimen name="control_corner_material">2dp</dimen>
+ <!-- Size of icon shown beside a preference locked by admin -->
+ <dimen name="restricted_icon_size_material">16dp</dimen>
+
<dimen name="edit_text_inset_horizontal_material">4dp</dimen>
<dimen name="edit_text_inset_top_material">10dp</dimen>
<dimen name="edit_text_inset_bottom_material">7dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c751af3d0c82..cc99a4e4e640 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2909,14 +2909,16 @@
<public name="opticalInsetBottom" />
<public name="allowForceDark" />
<public name="supportsAmbientMode" />
- </public-group>
-
- <public-group type="attr" first-id="0x0101058d">
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />
<public name="minimumUiTimeout" />
</public-group>
+ <public-group type="drawable" first-id="0x010800b4">
+ <!-- @hide @SystemApi -->
+ <public name="ic_info" />
+ </public-group>
+
<public-group type="style" first-id="0x010302e2">
</public-group>
@@ -2943,6 +2945,11 @@
<public name="config_sendPackageName" />
</public-group>
+ <public-group type="dimen" first-id="0x01050007">
+ <!-- @hide @SystemApi -->
+ <public name="config_restricted_icon_size" />
+ </public-group>
+
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1a5b7b6cb06a..64620f33b2df 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/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index e84aed1b2e38..fee470dce24d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -241,7 +241,6 @@ public class SettingsBackupTest {
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,
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 922b79aa008d..69d2828f20bc 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -57,7 +57,7 @@ public class AccessibilityNodeInfoTest {
// The number of flags held in boolean properties. Their values should also be double-checked
// in the methods above.
- private static final int NUM_BOOLEAN_PROPERTIES = 17;
+ private static final int NUM_BOOLEAN_PROPERTIES = 18;
@Test
public void testStandardActions_serializationFlagIsValid() {
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0eb3d06e79de..565a3ecd0411 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -342,6 +342,20 @@ public final class LooperStatsTest {
assertThat(looperStats.getEntries().get(0).messageCount).isEqualTo(2);
}
+ @Test
+ public void testReset() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 1);
+
+ Object token1 = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000));
+ Object token2 = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token2, mHandlerFirst.obtainMessage(2000));
+ looperStats.reset();
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(0);
+ }
+
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
try {
r.run();
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index c4017d15268f..73c10d238a60 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -210,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/libs/hwui/Android.bp b/libs/hwui/Android.bp
index b01136361101..11dad2e0d731 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -175,6 +175,7 @@ cc_defaults {
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/SkiaVulkanPipeline.cpp",
"pipeline/skia/VectorDrawableAtlas.cpp",
+ "pipeline/skia/VkFunctorDrawable.cpp",
"renderstate/RenderState.cpp",
"renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index b5b87d516ff7..21fbbdca7ad0 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -26,8 +26,6 @@
#include <log/log.h>
-#include <GLES2/gl2.h>
-
namespace android {
namespace uirenderer {
@@ -46,39 +44,12 @@ static constexpr android::DisplayInfo sDummyDisplay{
1920, // viewportH
};
-static DeviceInfo* sDeviceInfo = nullptr;
-static std::once_flag sInitializedFlag;
-
const DeviceInfo* DeviceInfo::get() {
- LOG_ALWAYS_FATAL_IF(!sDeviceInfo, "DeviceInfo not yet initialized.");
- return sDeviceInfo;
-}
-
-void DeviceInfo::initialize() {
- std::call_once(sInitializedFlag, []() {
- sDeviceInfo = new DeviceInfo();
- sDeviceInfo->load();
- });
-}
-
-void DeviceInfo::initialize(int maxTextureSize) {
- std::call_once(sInitializedFlag, [maxTextureSize]() {
- sDeviceInfo = new DeviceInfo();
- sDeviceInfo->mDisplayInfo = DeviceInfo::queryDisplayInfo();
- sDeviceInfo->mMaxTextureSize = maxTextureSize;
- sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace,
- &sDeviceInfo->mTargetPixelFormat);
- });
-}
-
-void DeviceInfo::load() {
- mDisplayInfo = queryDisplayInfo();
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
- sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace,
- &sDeviceInfo->mTargetPixelFormat);
+ static DeviceInfo sDeviceInfo;
+ return &sDeviceInfo;
}
-DisplayInfo DeviceInfo::queryDisplayInfo() {
+DisplayInfo QueryDisplayInfo() {
if (Properties::isolatedProcess) {
return sDummyDisplay;
}
@@ -90,17 +61,36 @@ DisplayInfo DeviceInfo::queryDisplayInfo() {
return displayInfo;
}
-void DeviceInfo::queryCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) {
+void QueryCompositionPreference(ui::Dataspace* dataSpace,
+ ui::PixelFormat* pixelFormat) {
if (Properties::isolatedProcess) {
*dataSpace = ui::Dataspace::V0_SRGB;
*pixelFormat = ui::PixelFormat::RGBA_8888;
}
status_t status =
- SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat);
+ SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat);
LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
}
+DeviceInfo::DeviceInfo() {
+#if HWUI_NULL_GPU
+ mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
+#else
+ mMaxTextureSize = -1;
+#endif
+ mDisplayInfo = QueryDisplayInfo();
+ QueryCompositionPreference(&mTargetDataSpace, &mTargetPixelFormat);
+}
+
+int DeviceInfo::maxTextureSize() const {
+ LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet.");
+ return mMaxTextureSize;
+}
+
+void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
+ const_cast<DeviceInfo*>(DeviceInfo::get())->mMaxTextureSize = maxTextureSize;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 416af179eb21..1d7477416077 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -19,51 +19,38 @@
#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
-#include "Extensions.h"
#include "utils/Macros.h"
namespace android {
namespace uirenderer {
+namespace renderthread {
+ class RenderThread;
+}
+
class DeviceInfo {
PREVENT_COPY_AND_ASSIGN(DeviceInfo);
public:
- // returns nullptr if DeviceInfo is not initialized yet
- // Note this does not have a memory fence so it's up to the caller
- // to use one if required. Normally this should not be necessary
static const DeviceInfo* get();
- // only call this after GL has been initialized, or at any point if compiled
- // with HWUI_NULL_GPU
- static void initialize();
- static void initialize(int maxTextureSize);
+ // this value is only valid after the GPU has been initialized and there is a valid graphics
+ // context or if you are using the HWUI_NULL_GPU
+ int maxTextureSize() const;
- int maxTextureSize() const { return mMaxTextureSize; }
ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; }
ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; }
const DisplayInfo& displayInfo() const { return mDisplayInfo; }
- const Extensions& extensions() const { return mExtensions; }
-
- static uint32_t multiplyByResolution(uint32_t in) {
- auto di = DeviceInfo::get()->displayInfo();
- return di.w * di.h * in;
- }
-
- static DisplayInfo queryDisplayInfo();
private:
- static void queryCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat);
+ friend class renderthread::RenderThread;
+ static void setMaxTextureSize(int maxTextureSize);
- DeviceInfo() {}
- ~DeviceInfo() {}
-
- void load();
+ DeviceInfo();
int mMaxTextureSize;
DisplayInfo mDisplayInfo;
- Extensions mExtensions;
+
// TODO(lpy) Replace below with android_ prefix types.
ui::Dataspace mTargetDataSpace;
ui::PixelFormat mTargetPixelFormat;
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
deleted file mode 100644
index e90f40c1c979..000000000000
--- a/libs/hwui/Extensions.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_EXTENSIONS_H
-#define ANDROID_HWUI_EXTENSIONS_H
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Classes
-///////////////////////////////////////////////////////////////////////////////
-
-class Extensions {
-public:
- Extensions() {}
-
- inline bool hasNPot() const { return false; }
- inline bool hasFramebufferFetch() const { return false; }
- inline bool hasDiscardFramebuffer() const { return false; }
- inline bool hasDebugMarker() const { return false; }
- inline bool has1BitStencil() const { return false; }
- inline bool has4BitStencil() const { return false; }
- inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
- inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
- inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
- inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
- inline bool hasRenderableFloatTextures() const {
- return (mVersionMajor >= 3 && mVersionMinor >= 2);
- }
- inline bool hasSRGB() const { return false; }
- inline bool hasSRGBWriteControl() const { return hasSRGB() && false; }
- inline bool hasLinearBlending() const { return hasSRGB() && false; }
-
- inline int getMajorGlVersion() const { return mVersionMajor; }
- inline int getMinorGlVersion() const { return mVersionMinor; }
-
-private:
- int mVersionMajor = 2;
- int mVersionMinor = 0;
-}; // class Extensions
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index ab80d3d98448..165fc4860fb2 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -45,7 +45,7 @@ static bool shouldTimeOutLocked() {
}
static void checkIdleTimeout() {
- std::lock_guard{sLock};
+ std::lock_guard _lock{sLock};
if (sPendingUploads == 0 && shouldTimeOutLocked()) {
sEglManager.destroy();
} else {
@@ -54,7 +54,7 @@ static void checkIdleTimeout() {
}
static void beginUpload() {
- std::lock_guard{sLock};
+ std::lock_guard _lock{sLock};
sPendingUploads++;
if (!sUploadThread) {
@@ -75,13 +75,13 @@ static void beginUpload() {
}
static void endUpload() {
- std::lock_guard{sLock};
+ std::lock_guard _lock{sLock};
sPendingUploads--;
sLastUpload = systemTime();
}
static EGLDisplay getUploadEglDisplay() {
- std::lock_guard{sLock};
+ std::lock_guard _lock{sLock};
LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
return sEglManager.eglDisplay();
}
@@ -107,39 +107,6 @@ static bool hasFP16Support() {
#define FENCE_TIMEOUT 2000000000
-class AutoEglImage {
-public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
- EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
- imageAttrs);
- }
-
- ~AutoEglImage() {
- if (image != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mDisplay, image);
- }
- }
-
- EGLImageKHR image = EGL_NO_IMAGE_KHR;
-
-private:
- EGLDisplay mDisplay = EGL_NO_DISPLAY;
-};
-
-class AutoSkiaGlTexture {
-public:
- AutoSkiaGlTexture() {
- glGenTextures(1, &mTexture);
- glBindTexture(GL_TEXTURE_2D, mTexture);
- }
-
- ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
-
-private:
- GLuint mTexture = 0;
-};
-
struct FormatInfo {
PixelFormat pixelFormat;
GLint format, type;
diff --git a/libs/hwui/debug/wrap_gles.h b/libs/hwui/debug/wrap_gles.h
index 27a29aa0a6b2..3da6e802d178 100644
--- a/libs/hwui/debug/wrap_gles.h
+++ b/libs/hwui/debug/wrap_gles.h
@@ -28,6 +28,9 @@
#include <GLES3/gl31.h>
#include <GLES3/gl32.h>
+// constant used by the NULL GPU implementation as well as HWUI's unit tests
+constexpr int NULL_GPU_MAX_TEXTURE_SIZE = 2048;
+
// Generate stubs that route all the calls to our function table
#include "gles_redefine.h"
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index dcfe6b371171..e4ba13da709c 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -138,7 +138,7 @@ protected:
renderNodeDrawable->getRenderNode()->output(mOutput, mLevel + 1);
return;
}
- auto glFunctorDrawable = getGLFunctorDrawable(drawable);
+ auto glFunctorDrawable = getFunctorDrawable(drawable);
if (nullptr != glFunctorDrawable) {
mOutput << std::string(mLevel * 2, ' ') << "drawGLFunctorDrawable" << std::endl;
return;
@@ -157,10 +157,10 @@ private:
return nullptr;
}
- GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) {
+ FunctorDrawable* getFunctorDrawable(SkDrawable* drawable) {
for (auto& child : mDisplayList.mChildFunctors) {
- if (drawable == &child) {
- return &child;
+ if (drawable == child) {
+ return child;
}
}
return nullptr;
diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h
new file mode 100644
index 000000000000..162d13762e1a
--- /dev/null
+++ b/libs/hwui/pipeline/skia/FunctorDrawable.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "GlFunctorLifecycleListener.h"
+
+#include <SkCanvas.h>
+#include <SkDrawable.h>
+
+#include <utils/Functor.h>
+
+namespace android {
+namespace uirenderer {
+
+namespace skiapipeline {
+
+/**
+ * This drawable wraps a functor enabling it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class FunctorDrawable : public SkDrawable {
+public:
+ FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+ : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
+ virtual ~FunctorDrawable() {}
+
+ virtual void syncFunctor() const = 0;
+
+protected:
+ virtual SkRect onGetBounds() override { return mBounds; }
+
+ Functor* mFunctor;
+ sp<GlFunctorLifecycleListener> mListener;
+ const SkRect mBounds;
+};
+
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index b0fec7a70699..90d5e715f8cd 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -18,7 +18,6 @@
#include <GrContext.h>
#include <private/hwui/DrawGlInfo.h>
#include "GlFunctorLifecycleListener.h"
-#include "Properties.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
@@ -80,11 +79,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
return;
}
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- canvas->clear(SK_ColorRED);
- return;
- }
-
GLuint fboID = 0;
SkISize fboSize;
if (!GetFboDetails(canvas, &fboID, &fboSize)) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index d9e65c95444e..dd6ef25f30c5 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -16,12 +16,8 @@
#pragma once
-#include "GlFunctorLifecycleListener.h"
+#include "FunctorDrawable.h"
-#include <SkCanvas.h>
-#include <SkDrawable.h>
-
-#include <utils/Functor.h>
#include <utils/RefBase.h>
namespace android {
@@ -33,22 +29,16 @@ namespace skiapipeline {
* This drawable wraps a OpenGL functor enabling it to be recorded into a list
* of Skia drawing commands.
*/
-class GLFunctorDrawable : public SkDrawable {
+class GLFunctorDrawable : public FunctorDrawable {
public:
GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
+ : FunctorDrawable(functor, listener, canvas) {}
virtual ~GLFunctorDrawable();
- void syncFunctor() const;
+ void syncFunctor() const override;
protected:
- virtual SkRect onGetBounds() override { return mBounds; }
virtual void onDraw(SkCanvas* canvas) override;
-
-private:
- Functor* mFunctor;
- sp<GlFunctorLifecycleListener> mListener;
- const SkRect mBounds;
};
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 82179a37f5be..78b64b2f01eb 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -29,7 +29,7 @@ namespace skiapipeline {
void SkiaDisplayList::syncContents() {
for (auto& functor : mChildFunctors) {
- functor.syncFunctor();
+ functor->syncFunctor();
}
for (auto& animatedImage : mAnimatedImages) {
animatedImage->syncProperties();
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 4f30f98e147d..4c7853931029 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -17,7 +17,7 @@
#pragma once
#include "hwui/AnimatedImageDrawable.h"
-#include "GLFunctorDrawable.h"
+#include "FunctorDrawable.h"
#include "RecordingCanvas.h"
#include "RenderNodeDrawable.h"
#include "TreeInfo.h"
@@ -77,7 +77,7 @@ public:
* that creates them. Allocator dtor invokes all SkDrawable dtors.
*/
template <class T, typename... Params>
- SkDrawable* allocateDrawable(Params&&... params) {
+ T* allocateDrawable(Params&&... params) {
return allocator.create<T>(std::forward<Params>(params)...);
}
@@ -155,7 +155,7 @@ public:
* cannot relocate.
*/
std::deque<RenderNodeDrawable> mChildNodes;
- std::deque<GLFunctorDrawable> mChildFunctors;
+ std::deque<FunctorDrawable*> mChildFunctors;
std::vector<SkImage*> mMutableImages;
std::vector<VectorDrawableRoot*> mVectorDrawables;
std::vector<AnimatedImageDrawable*> mAnimatedImages;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 83d7e6a361bc..3c281e78ddd5 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -23,6 +23,8 @@
#include "NinePatchUtils.h"
#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/GLFunctorDrawable.h"
+#include "pipeline/skia/VkFunctorDrawable.h"
namespace android {
namespace uirenderer {
@@ -118,9 +120,16 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) {
- // Drawable dtor will be invoked when mChildFunctors deque is cleared.
- mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
- drawDrawable(&mDisplayList->mChildFunctors.back());
+ FunctorDrawable* functorDrawable;
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener,
+ asSkCanvas());
+ } else {
+ functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener,
+ asSkCanvas());
+ }
+ mDisplayList->mChildFunctors.push_back(functorDrawable);
+ drawDrawable(functorDrawable);
}
class VectorDrawable : public SkDrawable {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 5cbe33debbce..e34f160467af 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -22,6 +22,7 @@
#include "SkiaProfileRenderer.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
+#include "VkFunctorDrawable.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -146,9 +147,7 @@ sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() {
}
void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
- // TODO: we currently don't support OpenGL WebView's
- DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
- (*functor)(mode, nullptr);
+ VkFunctorDrawable::vkInvokeFunctor(functor);
}
sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
new file mode 100644
index 000000000000..6486ddb05aac
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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 "VkFunctorDrawable.h"
+#include <private/hwui/DrawGlInfo.h>
+
+#include "renderthread/EglManager.h"
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
+#include <thread>
+#include <utils/Color.h>
+#include <utils/Trace.h>
+#include <utils/TraceUtils.h>
+
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <utils/GLUtils.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+static std::mutex sLock{};
+static ThreadBase* sGLDrawThread = nullptr;
+static renderthread::EglManager sEglManager;
+
+// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it.
+class ScopedDrawRequest {
+public:
+ ScopedDrawRequest() { beginDraw(); }
+private:
+ void beginDraw() {
+ std::lock_guard{sLock};
+
+ if (!sGLDrawThread) {
+ sGLDrawThread = new ThreadBase{};
+ }
+
+ if (!sGLDrawThread->isRunning()) {
+ sGLDrawThread->start("GLFunctorThread");
+ }
+
+ if (!sEglManager.hasEglContext()) {
+ sGLDrawThread->queue().runSync([]() {
+ sEglManager.initialize();
+ });
+ }
+ }
+};
+
+void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) {
+ ScopedDrawRequest _drawRequest{};
+ sGLDrawThread->queue().runSync([&]() {
+ EGLDisplay display = sEglManager.eglDisplay();
+ DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+ if (display != EGL_NO_DISPLAY) {
+ mode = DrawGlInfo::kModeProcess;
+ }
+ (*functor)(mode, nullptr);
+ });
+}
+
+#define FENCE_TIMEOUT 2000000000
+
+void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+ ATRACE_CALL();
+
+ if (canvas->getGrContext() == nullptr) {
+ SkDEBUGF(("Attempting to draw VkFunctor into an unsupported surface"));
+ return;
+ }
+
+ ScopedDrawRequest _drawRequest{};
+
+ SkImageInfo surfaceInfo = canvas->imageInfo();
+
+ if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) {
+ // Buffer will be used as an OpenGL ES render target.
+ mFrameBuffer = new GraphicBuffer(
+ //TODO: try to reduce the size of the buffer: possibly by using clip bounds.
+ static_cast<uint32_t>(surfaceInfo.width()),
+ static_cast<uint32_t>(surfaceInfo.height()),
+ ColorTypeToPixelFormat(surfaceInfo.colorType()),
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
+ std::string("VkFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + "]");
+ status_t error = mFrameBuffer->initCheck();
+ if (error < 0) {
+ ALOGW("VkFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
+ return;
+ }
+
+ mFBInfo = surfaceInfo;
+ }
+
+ //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan
+ //TODO: draw command has completed.
+ //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See
+ //TODO: GrVkGpu::destroyResources() for example.
+ bool success = sGLDrawThread->queue().runSync([&]() -> bool {
+ ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height());
+ EGLDisplay display = sEglManager.eglDisplay();
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
+ "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer();
+ AutoEglImage autoImage(display, clientBuffer);
+ if (autoImage.image == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image, err =%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ return false;
+ }
+
+ AutoSkiaGlTexture glTexture;
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+ GL_CHECKPOINT(MODERATE);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ DrawGlInfo info;
+ SkMatrix44 mat4(canvas->getTotalMatrix());
+ SkIRect clipBounds = canvas->getDeviceClipBounds();
+
+ info.clipLeft = clipBounds.fLeft;
+ info.clipTop = clipBounds.fTop;
+ info.clipRight = clipBounds.fRight;
+ info.clipBottom = clipBounds.fBottom;
+ info.isLayer = true;
+ info.width = mFBInfo.width();
+ info.height = mFBInfo.height();
+ mat4.asColMajorf(&info.transform[0]);
+
+ glViewport(0, 0, info.width, info.height);
+
+ AutoGLFramebuffer glFb;
+ // Bind texture to the frame buffer.
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ glTexture.mTexture, 0);
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Failed framebuffer check for created target buffer: %s",
+ GLUtils::getGLFramebufferError());
+ return false;
+ }
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ (*mFunctor)(DrawGlInfo::kModeDraw, &info);
+
+ EGLSyncKHR glDrawFinishedFence =
+ eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+ LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR,
+ "Could not create sync fence %#x", eglGetError());
+ glFlush();
+ // TODO: export EGLSyncKHR in file descr
+ // TODO: import file desc in Vulkan Semaphore
+ // TODO: instead block the GPU: probably by using external Vulkan semaphore.
+ // Block the CPU until the glFlush finish.
+ EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0,
+ FENCE_TIMEOUT);
+ LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+ "Failed to wait for the fence %#x", eglGetError());
+ eglDestroySyncKHR(display, glDrawFinishedFence);
+ return true;
+ });
+
+ if (!success) {
+ return;
+ }
+
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrcOver);
+ canvas->save();
+ // The size of the image matches the size of the canvas. We've used the matrix already, while
+ // drawing into the offscreen surface, so we need to reset it here.
+ canvas->resetMatrix();
+
+ auto functorImage = SkImage::MakeFromAHardwareBuffer(
+ reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType,
+ nullptr, kBottomLeft_GrSurfaceOrigin);
+ canvas->drawImage(functorImage, 0, 0, &paint);
+ canvas->restore();
+}
+
+VkFunctorDrawable::~VkFunctorDrawable() {
+ if (mListener.get() != nullptr) {
+ ScopedDrawRequest _drawRequest{};
+ sGLDrawThread->queue().runSync([&]() {
+ mListener->onGlFunctorReleased(mFunctor);
+ });
+ }
+}
+
+void VkFunctorDrawable::syncFunctor() const {
+ ScopedDrawRequest _drawRequest{};
+ sGLDrawThread->queue().runSync([&]() {
+ (*mFunctor)(DrawGlInfo::kModeSync, nullptr);
+ });
+}
+
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
new file mode 100644
index 000000000000..e37f6fb85090
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -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.
+ */
+
+#pragma once
+
+#include "FunctorDrawable.h"
+
+#include <utils/RefBase.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace uirenderer {
+
+namespace skiapipeline {
+
+/**
+ * This drawable wraps a Vulkan functor enabling it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class VkFunctorDrawable : public FunctorDrawable {
+public:
+ VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+ : FunctorDrawable(functor, listener, canvas) {}
+ virtual ~VkFunctorDrawable();
+
+ void syncFunctor() const override;
+
+ static void vkInvokeFunctor(Functor* functor);
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) override;
+
+private:
+
+ // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline.
+ sp<GraphicBuffer> mFrameBuffer;
+ SkImageInfo mFBInfo;
+};
+
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 675df4118876..0cb23e532064 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -23,7 +23,6 @@
#include "utils/Color.h"
#include "utils/StringUtils.h"
-#include "DeviceInfo.h"
#include "Frame.h"
#include "Properties.h"
@@ -127,7 +126,6 @@ void EglManager::initialize() {
createContext();
createPBufferSurface();
makeCurrent(mPBufferSurface, nullptr, /* force */ true);
- DeviceInfo::initialize();
mSurfaceColorGamut = DataSpaceToColorGamut(
static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 7258a0aa4f02..a5dcc72636d1 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -162,7 +162,7 @@ void RenderThread::initializeDisplayEventReceiver() {
}
void RenderThread::initThreadLocals() {
- mDisplayInfo = DeviceInfo::queryDisplayInfo();
+ mDisplayInfo = DeviceInfo::get()->displayInfo();
nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
mTimeLord.setFrameInterval(frameIntervalNanos);
initializeDisplayEventReceiver();
@@ -246,6 +246,9 @@ void RenderThread::setGrContext(sk_sp<GrContext> context) {
mGrContext->releaseResourcesAndAbandonContext();
}
mGrContext = std::move(context);
+ if (mGrContext) {
+ DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
+ }
}
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 038e13c513fd..488117253e7a 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,7 +16,6 @@
#include "VulkanManager.h"
-#include "DeviceInfo.h"
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
@@ -399,8 +398,6 @@ void VulkanManager::initialize() {
free_features_extensions_structs(features);
- DeviceInfo::initialize(mRenderThread.getGrContext()->maxRenderTargetSize());
-
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0e6582c59a36..c35f512553d8 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -16,7 +16,6 @@
#pragma once
-#include <DeviceInfo.h>
#include <DisplayList.h>
#include <Matrix.h>
#include <Properties.h>
@@ -179,12 +178,6 @@ public:
static sp<RenderNode> createNode(
int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, Canvas& canvas)> setup) {
-#if HWUI_NULL_GPU
- // if RenderNodes are being sync'd/used, device info will be needed, since
- // DeviceInfo::maxTextureSize() affects layer property
- DeviceInfo::initialize();
-#endif
-
sp<RenderNode> node = new RenderNode();
RenderProperties& props = node->mutateStagingProperties();
props.setLeftTopRightBottom(left, top, right, bottom);
@@ -202,12 +195,6 @@ public:
static sp<RenderNode> createNode(
int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, RecordingCanvasType& canvas)> setup) {
-#if HWUI_NULL_GPU
- // if RenderNodes are being sync'd/used, device info will be needed, since
- // DeviceInfo::maxTextureSize() affects layer property
- DeviceInfo::initialize();
-#endif
-
sp<RenderNode> node = new RenderNode();
RenderProperties& props = node->mutateStagingProperties();
props.setLeftTopRightBottom(left, top, right, bottom);
@@ -233,11 +220,6 @@ public:
std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)>
setup,
const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
-#if HWUI_NULL_GPU
- // if RenderNodes are being sync'd/used, device info will be needed, since
- // DeviceInfo::maxTextureSize() affects layer property
- DeviceInfo::initialize();
-#endif
sp<RenderNode> node = new RenderNode();
if (name) {
node->setName(name);
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
index 85655fc2728a..3e8e0576bf49 100644
--- a/libs/hwui/tests/unit/RenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -22,8 +22,6 @@ using namespace android;
using namespace android::uirenderer;
TEST(RenderProperties, layerValidity) {
- DeviceInfo::initialize();
-
const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
ASSERT_LE(2048, maxTextureSize);
ASSERT_GT(100000, maxTextureSize);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 6c398eea895f..415f9e8517ff 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -20,6 +20,7 @@
#include "AnimationContext.h"
#include "DamageAccumulator.h"
#include "IContextFactory.h"
+#include "pipeline/skia/GLFunctorDrawable.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
@@ -46,7 +47,8 @@ TEST(SkiaDisplayList, reset) {
SkCanvas dummyCanvas;
RenderNodeDrawable drawable(nullptr, &dummyCanvas);
skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas);
- skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas);
+ GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas);
+ skiaDL->mChildFunctors.push_back(&functorDrawable);
skiaDL->mMutableImages.push_back(nullptr);
skiaDL->mVectorDrawables.push_back(nullptr);
skiaDL->mProjectionReceiver = &drawable;
@@ -95,7 +97,8 @@ TEST(SkiaDisplayList, syncContexts) {
SkCanvas dummyCanvas;
TestUtils::MockFunctor functor;
- skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas);
+ GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
+ skiaDL.mChildFunctors.push_back(&functorDrawable);
SkRect bounds = SkRect::MakeWH(200, 200);
VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index d35fe4f01aa0..9f71e91629fb 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -72,6 +72,26 @@ SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) {
}
}
+android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
+ switch (colorType) {
+ case kRGBA_8888_SkColorType:
+ return PIXEL_FORMAT_RGBA_8888;
+ case kRGBA_F16_SkColorType:
+ return PIXEL_FORMAT_RGBA_FP16;
+ case kRGB_565_SkColorType:
+ return PIXEL_FORMAT_RGB_565;
+ case kRGB_888x_SkColorType:
+ return PIXEL_FORMAT_RGBX_8888;
+ case kRGBA_1010102_SkColorType:
+ return PIXEL_FORMAT_RGBA_1010102;
+ case kARGB_4444_SkColorType:
+ return PIXEL_FORMAT_RGBA_4444;
+ default:
+ ALOGW("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType);
+ return PIXEL_FORMAT_RGBA_8888;
+ }
+}
+
SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) {
switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT709:
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index ff0e755934f2..e935a0d5ec8b 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -18,6 +18,7 @@
#include <math.h>
#include <system/graphics.h>
+#include <ui/PixelFormat.h>
#include <SkColor.h>
#include <SkColorSpace.h>
@@ -116,6 +117,8 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
SkColorType PixelFormatToColorType(android_pixel_format pixelFormat);
+android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
+
SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace);
sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index bf27300029c6..fcd036c451e9 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -59,5 +59,22 @@ bool GLUtils::dumpGLErrors() {
#endif
}
+const char* GLUtils::getGLFramebufferError() {
+ switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
+ case GL_FRAMEBUFFER_COMPLETE:
+ return "GL_FRAMEBUFFER_COMPLETE";
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ return "GL_FRAMEBUFFER_UNSUPPORTED";
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+ default:
+ return "Unknown error";
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index debfb5d06944..ca8810bde070 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -20,6 +20,12 @@
#include <log/log.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
namespace android {
namespace uirenderer {
@@ -43,8 +49,53 @@ public:
*/
static bool dumpGLErrors();
+ static const char* getGLFramebufferError();
}; // class GLUtils
+class AutoEglImage {
+public:
+ AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+ EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ imageAttrs);
+ }
+
+ ~AutoEglImage() {
+ if (image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mDisplay, image);
+ }
+ }
+
+ EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
+private:
+ EGLDisplay mDisplay = EGL_NO_DISPLAY;
+};
+
+class AutoSkiaGlTexture {
+public:
+ AutoSkiaGlTexture() {
+ glGenTextures(1, &mTexture);
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+ }
+
+ ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
+
+ GLuint mTexture = 0;
+};
+
+class AutoGLFramebuffer {
+public:
+ AutoGLFramebuffer() {
+ glGenFramebuffers(1, &mFb);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFb);
+ }
+
+ ~AutoGLFramebuffer() { glDeleteFramebuffers(1, &mFb); }
+
+ GLuint mFb;
+};
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d1d605fc8399..1d27c03e1dcb 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -43,6 +43,8 @@ import java.nio.ReadOnlyBufferException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
@@ -3582,7 +3584,18 @@ final public class MediaCodec {
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private long mNativeContext;
+ private long mNativeContext = 0;
+ private final Lock mNativeContextLock = new ReentrantLock();
+
+ private final long lockAndGetContext() {
+ mNativeContextLock.lock();
+ return mNativeContext;
+ }
+
+ private final void setAndUnlockContext(long context) {
+ mNativeContext = context;
+ mNativeContextLock.unlock();
+ }
/** @hide */
public static class MediaImage extends Image {
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 6ae4d408fca2..61879003b8dc 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -544,29 +544,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
/**
- * Create a request parcel which can be routed to the native media
- * player using {@link #invoke(Parcel, Parcel)}. The Parcel
- * returned has the proper InterfaceToken set. The caller should
- * not overwrite that token, i.e it can only append data to the
- * Parcel.
- *
- * @return A parcel suitable to hold a request for the native
- * player.
- * {@hide}
- */
- @Override
- public Parcel newRequest() {
- Parcel parcel = Parcel.obtain();
- return parcel;
- }
-
- /**
* Invoke a generic method on the native player using opaque protocol
* buffer message for the request and reply. Both payloads' format is a
* convention between the java caller and the native player.
*
- * @param request PlayerMessage for the extension. The
- * caller must use {@link #newRequest()} to get one.
+ * @param msg PlayerMessage for the extension.
*
* @return PlayerMessage with the data returned by the
* native player.
@@ -1536,91 +1518,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
/**
- * Gets the media metadata.
- *
- * @param update_only controls whether the full set of available
- * metadata is returned or just the set that changed since the
- * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
- * #METADATA_ALL}.
- *
- * @param apply_filter if true only metadata that matches the
- * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
- * #BYPASS_METADATA_FILTER}.
- *
- * @return The metadata, possibly empty. null if an error occured.
- // FIXME: unhide.
- * {@hide}
- */
- @Override
- public Metadata getMetadata(final boolean update_only,
- final boolean apply_filter) {
- Parcel reply = Parcel.obtain();
- Metadata data = new Metadata();
-
- if (!native_getMetadata(update_only, apply_filter, reply)) {
- reply.recycle();
- return null;
- }
-
- // Metadata takes over the parcel, don't recycle it unless
- // there is an error.
- if (!data.parse(reply)) {
- reply.recycle();
- return null;
- }
- return data;
- }
-
- /**
- * Set a filter for the metadata update notification and update
- * retrieval. The caller provides 2 set of metadata keys, allowed
- * and blocked. The blocked set always takes precedence over the
- * allowed one.
- * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
- * shorthands to allow/block all or no metadata.
- *
- * By default, there is no filter set.
- *
- * @param allow Is the set of metadata the client is interested
- * in receiving new notifications for.
- * @param block Is the set of metadata the client is not interested
- * in receiving new notifications for.
- * @return The call status code.
- *
- // FIXME: unhide.
- * {@hide}
- */
- @Override
- public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
- // Do our serialization manually instead of calling
- // Parcel.writeArray since the sets are made of the same type
- // we avoid paying the price of calling writeValue (used by
- // writeArray) which burns an extra int per element to encode
- // the type.
- Parcel request = newRequest();
-
- // The parcel starts already with an interface token. There
- // are 2 filters. Each one starts with a 4bytes number to
- // store the len followed by a number of int (4 bytes as well)
- // representing the metadata type.
- int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
-
- if (request.dataCapacity() < capacity) {
- request.setDataCapacity(capacity);
- }
-
- request.writeInt(allow.size());
- for(Integer t: allow) {
- request.writeInt(t);
- }
- request.writeInt(block.size());
- for(Integer t: block) {
- request.writeInt(t);
- }
- return native_setMetadataFilter(request);
- }
-
- /**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
* data source and calling prepare().
@@ -1802,32 +1699,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private native void _setAuxEffectSendLevel(float level);
- /*
- * @param update_only If true fetch only the set of metadata that have
- * changed since the last invocation of getMetadata.
- * The set is built using the unfiltered
- * notifications the native player sent to the
- * MediaPlayer2Manager during that period of
- * time. If false, all the metadatas are considered.
- * @param apply_filter If true, once the metadata set has been built based on
- * the value update_only, the current filter is applied.
- * @param reply[out] On return contains the serialized
- * metadata. Valid only if the call was successful.
- * @return The status code.
- */
- private native final boolean native_getMetadata(boolean update_only,
- boolean apply_filter,
- Parcel reply);
-
- /*
- * @param request Parcel with the 2 serialized lists of allowed
- * metadata types followed by the one to be
- * dropped. Each list starts with an integer
- * indicating the number of metadata type elements.
- * @return The status code.
- */
- private native final int native_setMetadataFilter(Parcel request);
-
private static native final void native_init();
private native final void native_setup(Object mediaplayer2_this);
private native final void native_finalize();
@@ -1903,25 +1774,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mFormat = format;
}
- /**
- * Flatten this object in to a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
- * May be 0 or {@link android.os.Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
- */
- /* package private */ void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mTrackType);
- dest.writeString(getLanguage());
-
- if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
- dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
- }
- }
-
@Override
public String toString() {
StringBuilder out = new StringBuilder(128);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7681cc340069..3870124f295e 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -88,8 +88,6 @@ cc_library_shared {
name: "libmedia2_jni",
srcs: [
- "android_media_Media2HTTPConnection.cpp",
- "android_media_Media2HTTPService.cpp",
"android_media_Media2DataSource.cpp",
"android_media_MediaMetricsJNI.cpp",
"android_media_MediaPlayer2.cpp",
@@ -142,6 +140,7 @@ cc_library_shared {
"libstagefright_player2",
"libstagefright_rtsp",
"libstagefright_timedtext2",
+ "libmedia2_jni_core",
],
group_static_libs: true,
diff --git a/media/jni/android_media_Media2HTTPConnection.cpp b/media/jni/android_media_Media2HTTPConnection.cpp
deleted file mode 100644
index d02ee06dba49..000000000000
--- a/media/jni/android_media_Media2HTTPConnection.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Media2HTTPConnection-JNI"
-#include <utils/Log.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/ScopedLocalRef.h>
-
-#include "android_media_Media2HTTPConnection.h"
-#include "android_util_Binder.h"
-
-#include "log/log.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-namespace android {
-
-static const size_t kBufferSize = 32768;
-
-JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
- mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPConnectionObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPConnectionClass(
- env, env->GetObjectClass(mMedia2HTTPConnectionObj));
- CHECK(media2HTTPConnectionClass.get() != NULL);
-
- mConnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "connect",
- "(Ljava/lang/String;Ljava/lang/String;)Z");
- CHECK(mConnectMethod != NULL);
-
- mDisconnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "disconnect",
- "()V");
- CHECK(mDisconnectMethod != NULL);
-
- mReadAtMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "readAt",
- "(J[BI)I");
- CHECK(mReadAtMethod != NULL);
-
- mGetSizeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getSize",
- "()J");
- CHECK(mGetSizeMethod != NULL);
-
- mGetMIMETypeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getMIMEType",
- "()Ljava/lang/String;");
- CHECK(mGetMIMETypeMethod != NULL);
-
- mGetUriMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getUri",
- "()Ljava/lang/String;");
- CHECK(mGetUriMethod != NULL);
-
- ScopedLocalRef<jbyteArray> tmp(
- env, env->NewByteArray(kBufferSize));
- mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
- CHECK(mByteArrayObj != NULL);
-}
-
-JMedia2HTTPConnection::~JMedia2HTTPConnection() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
- env->DeleteGlobalRef(mByteArrayObj);
-}
-
-bool JMedia2HTTPConnection::connect(
- const char *uri, const KeyedVector<String8, String8> *headers) {
- String8 tmp("");
- if (headers != NULL) {
- for (size_t i = 0; i < headers->size(); ++i) {
- tmp.append(headers->keyAt(i));
- tmp.append(String8(": "));
- tmp.append(headers->valueAt(i));
- tmp.append(String8("\r\n"));
- }
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = env->NewStringUTF(uri);
- jstring jheaders = env->NewStringUTF(tmp.string());
-
- jboolean ret =
- env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
-
- env->DeleteLocalRef(juri);
- env->DeleteLocalRef(jheaders);
-
- return (bool)ret;
-}
-
-void JMedia2HTTPConnection::disconnect() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
-}
-
-ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
-
- if (size > kBufferSize) {
- size = kBufferSize;
- }
-
- jint n = env->CallIntMethod(
- mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
-
- if (n > 0) {
- env->GetByteArrayRegion(
- mByteArrayObj,
- 0,
- n,
- (jbyte *)data);
- }
-
- return n;
-}
-
-off64_t JMedia2HTTPConnection::getSize() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
-}
-
-status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(jmime, 0);
- if (str != NULL) {
- *mimeType = String8(str);
- } else {
- *mimeType = "application/octet-stream";
- }
- env->ReleaseStringUTFChars(jmime, str);
- return OK;
-}
-
-status_t JMedia2HTTPConnection::getUri(String8 *uri) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(juri, 0);
- *uri = String8(str);
- env->ReleaseStringUTFChars(juri, str);
- return OK;
-}
-
-} // namespace android
diff --git a/media/jni/android_media_Media2HTTPConnection.h b/media/jni/android_media_Media2HTTPConnection.h
deleted file mode 100644
index 14bc677f931b..000000000000
--- a/media/jni/android_media_Media2HTTPConnection.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
-#define _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPConnection : public MediaHTTPConnection {
- JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
-
- virtual bool connect(
- const char *uri, const KeyedVector<String8, String8> *headers) override;
-
- virtual void disconnect() override;
- virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
- virtual off64_t getSize() override;
- virtual status_t getMIMEType(String8 *mimeType) override;
- virtual status_t getUri(String8 *uri) override;
-
-protected:
- virtual ~JMedia2HTTPConnection();
-
-private:
- jobject mMedia2HTTPConnectionObj;
- jmethodID mConnectMethod;
- jmethodID mDisconnectMethod;
- jmethodID mReadAtMethod;
- jmethodID mGetSizeMethod;
- jmethodID mGetMIMETypeMethod;
- jmethodID mGetUriMethod;
-
- jbyteArray mByteArrayObj;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
-};
-
-} // namespace android
-
-#endif // _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
diff --git a/media/jni/android_media_Media2HTTPService.cpp b/media/jni/android_media_Media2HTTPService.cpp
deleted file mode 100644
index 1c63889e2939..000000000000
--- a/media/jni/android_media_Media2HTTPService.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Media2HTTPService-JNI"
-#include <utils/Log.h>
-
-#include "android_media_Media2HTTPConnection.h"
-#include "android_media_Media2HTTPService.h"
-
-#include "log/log.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/ScopedLocalRef.h>
-
-namespace android {
-
-JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
- mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPServiceObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
- CHECK(media2HTTPServiceClass.get() != NULL);
-
- mMakeHTTPConnectionMethod = env->GetMethodID(
- media2HTTPServiceClass.get(),
- "makeHTTPConnection",
- "()Landroid/media/Media2HTTPConnection;");
- CHECK(mMakeHTTPConnectionMethod != NULL);
-}
-
-JMedia2HTTPService::~JMedia2HTTPService() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPServiceObj);
-}
-
-sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jobject media2HTTPConnectionObj =
- env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
-
- return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
-}
-
-} // namespace android
diff --git a/media/jni/android_media_Media2HTTPService.h b/media/jni/android_media_Media2HTTPService.h
deleted file mode 100644
index 30d03f5309b1..000000000000
--- a/media/jni/android_media_Media2HTTPService.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
-#define _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPService : public MediaHTTPService {
- JMedia2HTTPService(JNIEnv *env, jobject thiz);
-
- virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
-
-protected:
- virtual ~JMedia2HTTPService();
-
-private:
- jobject mMedia2HTTPServiceObj;
-
- jmethodID mMakeHTTPConnectionMethod;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
-};
-
-} // namespace android
-
-#endif // _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 3490ff8fcf43..503720939113 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -108,8 +108,9 @@ static struct {
} gCodecInfo;
struct fields_t {
- jfieldID context;
jmethodID postEventFromNativeID;
+ jmethodID lockAndGetContextID;
+ jmethodID setAndUnlockContextID;
jfieldID cryptoInfoNumSubSamplesID;
jfieldID cryptoInfoNumBytesOfClearDataID;
jfieldID cryptoInfoNumBytesOfEncryptedDataID;
@@ -931,7 +932,7 @@ using namespace android;
static sp<JMediaCodec> setMediaCodec(
JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
- sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
+ sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
if (codec != NULL) {
codec->incStrong(thiz);
}
@@ -944,13 +945,15 @@ static sp<JMediaCodec> setMediaCodec(
old->release();
old->decStrong(thiz);
}
- env->SetLongField(thiz, gFields.context, (jlong)codec.get());
+ env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
return old;
}
static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
- return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
+ sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
+ env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
+ return codec;
}
static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
@@ -1876,15 +1879,21 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
env, env->FindClass("android/media/MediaCodec"));
CHECK(clazz.get() != NULL);
- gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
- CHECK(gFields.context != NULL);
-
gFields.postEventFromNativeID =
env->GetMethodID(
clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
-
CHECK(gFields.postEventFromNativeID != NULL);
+ gFields.lockAndGetContextID =
+ env->GetMethodID(
+ clazz.get(), "lockAndGetContext", "()J");
+ CHECK(gFields.lockAndGetContextID != NULL);
+
+ gFields.setAndUnlockContextID =
+ env->GetMethodID(
+ clazz.get(), "setAndUnlockContext", "(J)V");
+ CHECK(gFields.setAndUnlockContextID != NULL);
+
jfieldID field;
field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
CHECK(field != NULL);
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index d4c84b5b6c77..1a844cc678c6 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -30,6 +30,7 @@
#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
#include <mediaplayer2/JAudioTrack.h>
#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
#include <mediaplayer2/mediaplayer2.h>
#include <stdio.h>
#include <assert.h>
@@ -45,7 +46,6 @@
#include "utils/KeyedVector.h"
#include "utils/String8.h"
#include "android_media_BufferingParams.h"
-#include "android_media_Media2HTTPService.h"
#include "android_media_Media2DataSource.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 212f398aa163..0ccf13e23aaf 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -107,6 +107,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dip"
android:elevation="@dimen/preview_controls_elevation"
+ android:tint="?android:attr/textColorPrimaryInverse"
android:background="@drawable/print_button">
</ImageButton>
diff --git a/packages/SettingsLib/HelpUtils/res/values/strings.xml b/packages/SettingsLib/HelpUtils/res/values/strings.xml
index ae07f5de852b..3e882bcc5754 100644
--- a/packages/SettingsLib/HelpUtils/res/values/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Label for Help and feedback menu item -->
+ <!-- Label for Help and feedback menu item [CHAR LIMIT=45]-->
<string name="help_feedback_label">Help &amp; feedback</string>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index d4c9794bda63..b2f088257bb9 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp
@@ -2,6 +2,7 @@ android_library {
name: "SettingsLibRestrictedLockUtils",
srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
libs: [
"androidx.annotation_annotation",
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
index 724a524ad46a..0f02abd94216 100644
--- a/packages/SettingsLib/res/layout/restricted_icon.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
@@ -15,6 +15,7 @@
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/restricted_icon"
- android:layout_width="@dimen/restricted_icon_size"
- android:layout_height="@dimen/restricted_icon_size"
- android:src="@drawable/ic_info" /> \ No newline at end of file
+ android:layout_width="@*android:dimen/config_restricted_icon_size"
+ android:layout_height="@*android:dimen/config_restricted_icon_size"
+ android:tint="?android:attr/colorAccent"
+ android:src="@*android:drawable/ic_info" />
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
new file mode 100644
index 000000000000..7e4460ba815d
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+ <string name="enabled_by_admin">Enabled by admin</string>
+ <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
+ <string name="disabled_by_admin">Disabled by admin</string>
+
+</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
index b286df0e52e3..e1f6cdf57101 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -16,9 +16,10 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/restricted_icon"
- android:layout_width="@dimen/restricted_icon_size"
- android:layout_height="@dimen/restricted_icon_size"
- android:src="@drawable/ic_info"
+ android:layout_width="@*android:dimen/config_restricted_icon_size"
+ android:layout_height="@*android:dimen/config_restricted_icon_size"
+ android:tint="?android:attr/colorAccent"
+ android:src="@*android:drawable/ic_info"
android:gravity="end|center_vertical" />
<!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
@@ -28,4 +29,4 @@
android:focusable="false"
android:clickable="false"
android:background="@null" />
-</merge> \ No newline at end of file
+</merge>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 8094b021fa00..a9c5061f6d87 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -36,7 +36,6 @@
<dimen name="two_target_pref_medium_icon_size">32dp</dimen>
<!-- Lock icon for preferences locked by admin -->
- <dimen name="restricted_icon_size">16dp</dimen>
<dimen name="restricted_icon_padding">4dp</dimen>
<dimen name="wifi_preference_badge_padding">8dip</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ea6844ef2740..332ced66ef77 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -965,11 +965,6 @@
<!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
<string name="disabled_by_admin_summary_text">Controlled by admin</string>
- <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
- <string name="enabled_by_admin">Enabled by admin</string>
- <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
- <string name="disabled_by_admin">Disabled by admin</string>
-
<!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
<string name="disabled">Disabled</string>
<!-- Summary of app trusted to install apps [CHAR LIMIT=45] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 0094c2c32ef8..c03ba9a93294 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -55,9 +56,15 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
* @return drawables for displaying with settings that are locked by a device admin.
*/
public static Drawable getRestrictedPadlock(Context context) {
- Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
+ Drawable restrictedPadlock = context.getDrawable(android.R.drawable.ic_info);
final int iconSize = context.getResources().getDimensionPixelSize(
- R.dimen.restricted_icon_size);
+ android.R.dimen.config_restricted_icon_size);
+
+ TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ restrictedPadlock.setTint(colorAccent);
+
restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
return restrictedPadlock;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index e8f47e18b4e3..5a64e02cece4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -211,6 +211,26 @@ public class CachedBluetoothDeviceManager {
}
}
+ /**
+ * Attempts to get the name of a remote device, otherwise returns the address.
+ *
+ * @param device The remote device.
+ * @return The name, or if unavailable, the address.
+ */
+ public String getName(BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = findDevice(device);
+ if (cachedDevice != null && cachedDevice.getName() != null) {
+ return cachedDevice.getName();
+ }
+
+ String name = device.getAliasName();
+ if (name != null) {
+ return name;
+ }
+
+ return device.getAddress();
+ }
+
public synchronized void clearNonBondedDevices() {
mCachedDevicesMapForHearingAids.entrySet().removeIf(entries
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 8c4bff5bc4ff..c8d4fc84f4b4 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 com.android.settingslib.R;
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 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
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 CachedBluetoothDeviceManager mDeviceManager;
private final LocalBluetoothProfileManager mProfileManager;
@@ -59,9 +58,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
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();
@@ -81,9 +78,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (DEBUG) {
- Log.d(TAG, "Bluetooth service disconnected");
- }
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
@@ -110,6 +105,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
@Override
public boolean connect(BluetoothDevice device) {
+ // Don't invoke method in service because settings is not allowed to connect this profile.
return false;
}
@@ -126,11 +122,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
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
@@ -185,9 +177,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
}
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/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 7d334eb31a19..7ad2e28c84b5 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.ArrayList;
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;
@@ -60,7 +59,7 @@ public final class MapClientProfile implements LocalBluetoothProfile {
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();
@@ -82,14 +81,14 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
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;
}
@@ -115,18 +114,16 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
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);
@@ -135,23 +132,30 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
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);
@@ -162,7 +166,9 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
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,
@@ -200,11 +206,11 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
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/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index b295f2425280..8fefb2fc01b8 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 @@ import java.util.List;
public final class PbapClientProfile implements LocalBluetoothProfile {
private static final String TAG = "PbapClientProfile";
- private static boolean V = false;
private BluetoothPbapClient mService;
private boolean mIsProfileReady;
@@ -56,9 +55,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
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();
@@ -77,9 +74,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) {
- Log.d(TAG,"Bluetooth service disconnected");
- }
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
@@ -131,31 +126,16 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
}
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;
}
@@ -218,9 +198,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
}
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/net/NetworkStatsDetailLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java
new file mode 100644
index 000000000000..a070b2a5f768
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java
@@ -0,0 +1,117 @@
+/*
+ * 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.net;
+
+import android.app.usage.NetworkStatsManager;
+import android.app.usage.NetworkStats;
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import androidx.loader.content.AsyncTaskLoader;
+
+/**
+ * Loader for retrieving the network stats details for all UIDs.
+ */
+public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {
+
+ private static final String TAG = "NetworkDetailLoader";
+ private final NetworkStatsManager mNetworkStatsManager;
+ private final TelephonyManager mTelephonyManager;
+ private final long mStart;
+ private final long mEnd;
+ private final int mSubId;
+ private final int mNetworkType;
+
+ private NetworkStatsDetailLoader(Builder builder) {
+ super(builder.mContext);
+ mStart = builder.mStart;
+ mEnd = builder.mEnd;
+ mSubId = builder.mSubId;
+ mNetworkType = builder.mNetworkType;
+ mNetworkStatsManager = (NetworkStatsManager)
+ builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
+ mTelephonyManager =
+ (TelephonyManager) builder.mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ forceLoad();
+ }
+
+ @Override
+ public NetworkStats loadInBackground() {
+ try {
+ return mNetworkStatsManager.queryDetails(
+ mNetworkType, mTelephonyManager.getSubscriberId(mSubId), mStart, mEnd);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ super.onStopLoading();
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ cancelLoad();
+ }
+
+ public static class Builder {
+ private final Context mContext;
+ private long mStart;
+ private long mEnd;
+ private int mSubId;
+ private int mNetworkType;
+
+ public Builder(Context context) {
+ mContext = context;
+ }
+
+ public Builder setStartTime(long start) {
+ mStart = start;
+ return this;
+ }
+
+ public Builder setEndTime(long end) {
+ mEnd = end;
+ return this;
+ }
+
+ public Builder setSubscriptionId(int subId) {
+ mSubId = subId;
+ return this;
+ }
+
+ public Builder setNetworkType(int networkType) {
+ mNetworkType = networkType;
+ return this;
+ }
+
+ public NetworkStatsDetailLoader build() {
+ return new NetworkStatsDetailLoader(this);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
index c311337d6cf5..82bb0115c66f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
@@ -25,6 +25,12 @@ import android.os.RemoteException;
import androidx.loader.content.AsyncTaskLoader;
+/**
+ * Deprecated in favor of {@link NetworkStatsDetailLoader}
+ *
+ * @deprecated
+ */
+@Deprecated
public class SummaryForAllUidLoaderCompat extends AsyncTaskLoader<NetworkStats> {
private static final String KEY_TEMPLATE = "template";
private static final String KEY_START = "start";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
index dde17462a6f9..0ca2e87de336 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
@@ -52,6 +52,8 @@ public class SettingsLibRobolectricTestRunner extends RobolectricTestRunner {
@Override
public List<ResourcePath> getIncludedResourcePaths() {
final List<ResourcePath> paths = super.getIncludedResourcePaths();
+ paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/HelpUtils/res"));
+ paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/RestrictedLockUtils/res"));
paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res"));
paths.add(resourcePath("file:frameworks/base/core/res/res"));
paths.add(resourcePath("file:out/soong/.intermediates/prebuilts/sdk/current/androidx/androidx.appcompat_appcompat-nodeps/android_common/aar/res/"));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 8ac611fda1fc..7baded8da1d4 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
@@ -139,7 +139,7 @@ public class CachedBluetoothDeviceManagerTest {
public void testGetName_validCachedDevice_nameFound() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
assertThat(cachedDevice1).isNotNull();
- assertThat(mCachedDeviceManager.findDevice(mDevice1).getName()).isEqualTo(DEVICE_ALIAS_1);
+ assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1);
}
/**
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 000000000000..c91ee22d8587
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDevice;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class HidDeviceProfileTest {
+
+ @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;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mProfile = new HidDeviceProfile(RuntimeEnvironment.application,
+ mDeviceManager, mProfileManager);
+ mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+ 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/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
new file mode 100644
index 000000000000..c4c48a8bce8c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.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.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class MapClientProfileTest {
+
+ @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;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mProfile = new MapClientProfile(RuntimeEnvironment.application,
+ mDeviceManager, mProfileManager);
+ mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+ 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 000000000000..e4a444c836ab
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.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.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class PbapClientProfileTest {
+
+ @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;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mProfile = new PbapClientProfile(RuntimeEnvironment.application,
+ mDeviceManager, mProfileManager);
+ mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+ 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/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
index a501ffa1200e..40e7386cf5af 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -77,10 +77,10 @@ public class TileTest {
@Test
public void getIcon_hasIconMetadata_returnIcon() {
- mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, R.drawable.ic_info);
+ mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, android.R.drawable.ic_info);
assertThat(mTile.getIcon(RuntimeEnvironment.application).getResId())
- .isEqualTo(R.drawable.ic_info);
+ .isEqualTo(android.R.drawable.ic_info);
}
@Test
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index b047efbdc6e0..8a3a0b19c892 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -19,7 +19,6 @@
android:id="@+id/menu_container"
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
- android:focusable="false"
android:importantForAccessibility="no"
>
<!-- Use nav button width & height=match_parent for parent FrameLayout and buttons because they
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 26eadb5bfa2d..c168d4e6d7b2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -955,7 +955,7 @@
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
<dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
- <dimen name="nav_home_back_gesture_drag_limit">60dp</dimen>
+ <dimen name="nav_home_back_gesture_drag_limit">40dp</dimen>
<!-- Navigation bar shadow params. -->
<dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index cc1b9e8f9c49..bde7f1bd86ad 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.ServiceState;
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;
@@ -318,8 +319,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
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)) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ca1b48901c9d..123fca71deaf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -391,6 +391,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
position = mPages.size() - 1 - position;
}
ViewGroup view = mPages.get(position);
+ if (view.getParent() != null) {
+ container.removeView(view);
+ }
container.addView(view);
updateListening();
return view;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index d7abb387c278..177362cf60aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -16,23 +16,16 @@
package com.android.systemui.recents.events;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
-import android.util.MutableBoolean;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
-import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -117,11 +110,7 @@ class EventHandlerMethod {
* <p>
* Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber
* on the main application thread. Publishers can send() events to synchronously call subscribers
- * of that event, or post() events to be processed in the next run of the {@link Looper}. In
- * addition, the EventBus supports sending and handling {@link EventBus.InterprocessEvent}s
- * (within the same package) implemented using standard {@link BroadcastReceiver} mechanism.
- * Interprocess events must be posted using postInterprocess() to ensure that it is dispatched
- * correctly across processes.
+ * of that event, or post() events to be processed in the next run of the {@link Looper}.
*
* <p>
* Subscribers must be registered with a particular EventBus before they will receive events, and
@@ -135,26 +124,12 @@ class EventHandlerMethod {
* <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event}
* </ul>
*
- * <p>
- * Interprocess-Event method signature:<ul>
- * <li>Methods must be public final
- * <li>Methods must return void
- * <li>Methods must be called "onInterprocessBusEvent"
- * <li>Methods must take one parameter, of class type deriving from {@link EventBus.InterprocessEvent}
- * </ul>
- * </p>
- *
* </p>
* Each subscriber can be registered with a given priority (default 1), and events will be dispatch
* in decreasing order of priority. For subscribers with the same priority, events will be
* dispatched by latest registration time to earliest.
*
* <p>
- * Interprocess events must extend {@link EventBus.InterprocessEvent}, have a constructor which
- * takes a {@link Bundle} and implement toBundle(). This allows us to serialize events to be sent
- * across processes.
- *
- * <p>
* Caveats:<ul>
* <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so
* there must be another strong reference to the publisher for it to not get garbage-collected and
@@ -201,7 +176,7 @@ class EventHandlerMethod {
* result?
* </p>
*/
-public class EventBus extends BroadcastReceiver {
+public class EventBus {
private static final String TAG = "EventBus";
private static final boolean DEBUG_TRACE_ALL = false;
@@ -314,35 +289,6 @@ public class EventBus extends BroadcastReceiver {
}
/**
- * An inter-process event super class that allows us to track user state across subscriber
- * invocations.
- */
- public static class InterprocessEvent extends Event {
- private static final String EXTRA_USER = "_user";
-
- // The user which this event originated from
- public final int user;
-
- // Only accessible from derived events
- protected InterprocessEvent(int user) {
- this.user = user;
- }
-
- /**
- * Called from the event bus
- */
- protected InterprocessEvent(Bundle b) {
- user = b.getInt(EXTRA_USER);
- }
-
- protected Bundle toBundle() {
- Bundle b = new Bundle();
- b.putInt(EXTRA_USER, user);
- return b;
- }
- }
-
- /**
* Proguard must also know, and keep, all methods matching this signature.
*
* -keepclassmembers class ** {
@@ -351,13 +297,6 @@ public class EventBus extends BroadcastReceiver {
* }
*/
private static final String METHOD_PREFIX = "onBusEvent";
- private static final String INTERPROCESS_METHOD_PREFIX = "onInterprocessBusEvent";
-
- // Ensures that interprocess events can only be sent from a process holding this permission. */
- private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-
- // Used for passing event data across process boundaries
- private static final String EXTRA_INTERPROCESS_EVENT_BUNDLE = "interprocess_event_bundle";
// The default priority of all subscribers
private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
@@ -383,10 +322,6 @@ public class EventBus extends BroadcastReceiver {
// The handler to post all events
private Handler mHandler;
- // Keep track of whether we have registered a broadcast receiver already, so that we can
- // unregister ourselves before re-registering again with a new IntentFilter.
- private boolean mHasRegisteredReceiver;
-
/**
* Map from event class -> event handler list. Keeps track of the actual mapping from event
* to subscriber method.
@@ -401,13 +336,6 @@ public class EventBus extends BroadcastReceiver {
private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>();
/**
- * Map from interprocess event name -> interprocess event class. Used for mapping the event
- * name after receiving the broadcast, to the event type. After which a new instance is created
- * and posted in the local process.
- */
- private HashMap<String, Class<? extends InterprocessEvent>> mInterprocessEventNameMap = new HashMap<>();
-
- /**
* Set of all currently registered subscribers
*/
private ArrayList<Subscriber> mSubscribers = new ArrayList<>();
@@ -447,7 +375,7 @@ public class EventBus extends BroadcastReceiver {
* be scanned for appropriate event handler methods.
*/
public void register(Object subscriber) {
- registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null);
+ registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
}
/**
@@ -460,44 +388,7 @@ public class EventBus extends BroadcastReceiver {
* subscribers
*/
public void register(Object subscriber, int priority) {
- registerSubscriber(subscriber, priority, null);
- }
-
- /**
- * Explicitly registers a subscriber to receive interprocess events with the default priority.
- *
- * @param subscriber the subscriber to handle events. If this is the first instance of the
- * subscriber's class type that has been registered, the class's methods will
- * be scanned for appropriate event handler methods.
- */
- public void registerInterprocessAsCurrentUser(Context context, Object subscriber) {
- registerInterprocessAsCurrentUser(context, subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
- }
-
- /**
- * Registers a subscriber to receive interprocess events with the given priority.
- *
- * @param subscriber the subscriber to handle events. If this is the first instance of the
- * subscriber's class type that has been registered, the class's methods will
- * be scanned for appropriate event handler methods.
- * @param priority the priority that this subscriber will receive events relative to other
- * subscribers
- */
- public void registerInterprocessAsCurrentUser(Context context, Object subscriber, int priority) {
- if (DEBUG_TRACE_ALL) {
- logWithPid("registerInterprocessAsCurrentUser(" + subscriber.getClass().getSimpleName() + ")");
- }
-
- // Register the subscriber normally, and update the broadcast receiver filter if this is
- // a new subscriber type with interprocess events
- MutableBoolean hasInterprocessEventsChanged = new MutableBoolean(false);
- registerSubscriber(subscriber, priority, hasInterprocessEventsChanged);
- if (DEBUG_TRACE_ALL) {
- logWithPid("hasInterprocessEventsChanged: " + hasInterprocessEventsChanged.value);
- }
- if (hasInterprocessEventsChanged.value) {
- registerReceiverForInterprocessEvents(context);
- }
+ registerSubscriber(subscriber, priority);
}
/**
@@ -538,18 +429,6 @@ public class EventBus extends BroadcastReceiver {
}
/**
- * Explicit unregistration for interprocess event subscribers. This actually behaves exactly
- * the same as unregister() since we also do not want to stop listening for specific
- * inter-process messages in case new instances of that subscriber is registered.
- */
- public void unregisterInterprocess(Context context, Object subscriber) {
- if (DEBUG_TRACE_ALL) {
- logWithPid("unregisterInterprocess()");
- }
- unregister(subscriber);
- }
-
- /**
* Sends an event to the subscribers of the given event type immediately. This can only be
* called from the same thread as the EventBus's looper thread (for the default EventBus, this
* is the main application thread).
@@ -599,57 +478,6 @@ public class EventBus extends BroadcastReceiver {
}
}
- /** Prevent post()ing an InterprocessEvent */
- @Deprecated
- public void post(InterprocessEvent event) {
- throw new RuntimeException("Not supported, use postInterprocess");
- }
-
- /** Prevent send()ing an InterprocessEvent */
- @Deprecated
- public void send(InterprocessEvent event) {
- throw new RuntimeException("Not supported, use postInterprocess");
- }
-
- /**
- * Posts an interprocess event.
- */
- public void postInterprocess(Context context, final InterprocessEvent event) {
- if (DEBUG_TRACE_ALL) {
- logWithPid("postInterprocess(" + event.getClass().getSimpleName() + ")");
- }
- String eventType = event.getClass().getName();
- Bundle eventBundle = event.toBundle();
- Intent intent = new Intent(eventType);
- intent.setPackage(context.getPackageName());
- intent.putExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE, eventBundle);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
- Intent.FLAG_RECEIVER_FOREGROUND);
- context.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
-
- /**
- * Receiver for interprocess events.
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG_TRACE_ALL) {
- logWithPid("onReceive(" + intent.getAction() + ", user " + UserHandle.myUserId() + ")");
- }
-
- Bundle eventBundle = intent.getBundleExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE);
- Class<? extends InterprocessEvent> eventType = mInterprocessEventNameMap.get(intent.getAction());
- try {
- Constructor<? extends InterprocessEvent> ctor = eventType.getConstructor(Bundle.class);
- send((Event) ctor.newInstance(eventBundle));
- } catch (NoSuchMethodException|
- InvocationTargetException|
- InstantiationException|
- IllegalAccessException e) {
- Log.e(TAG, "Failed to create InterprocessEvent", e.getCause());
- }
- }
-
/**
* @return a dump of the current state of the EventBus
*/
@@ -711,8 +539,7 @@ public class EventBus extends BroadcastReceiver {
/**
* Registers a new subscriber.
*/
- private void registerSubscriber(Object subscriber, int priority,
- MutableBoolean hasInterprocessEventsChangedOut) {
+ private void registerSubscriber(Object subscriber, int priority) {
// Fail immediately if we are being called from the non-main thread
long callingThreadId = Thread.currentThread().getId();
if (callingThreadId != mHandler.getLooper().getThread().getId()) {
@@ -759,32 +586,16 @@ public class EventBus extends BroadcastReceiver {
}
// Find all the valid event bus handler methods of the subscriber
- MutableBoolean isInterprocessEvent = new MutableBoolean(false);
Method[] methods = subscriberType.getDeclaredMethods();
for (Method m : methods) {
Class<?>[] parameterTypes = m.getParameterTypes();
- isInterprocessEvent.value = false;
- if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {
+ if (isValidEventBusHandlerMethod(m, parameterTypes)) {
Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);
if (eventTypeHandlers == null) {
eventTypeHandlers = new ArrayList<>();
mEventTypeMap.put(eventType, eventTypeHandlers);
}
- if (isInterprocessEvent.value) {
- try {
- // Enforce that the event must have a Bundle constructor
- eventType.getConstructor(Bundle.class);
-
- mInterprocessEventNameMap.put(eventType.getName(),
- (Class<? extends InterprocessEvent>) eventType);
- if (hasInterprocessEventsChangedOut != null) {
- hasInterprocessEventsChangedOut.value = true;
- }
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor");
- }
- }
EventHandlerMethod method = new EventHandlerMethod(m, eventType);
EventHandler handler = new EventHandler(sub, method, priority);
eventTypeHandlers.add(handler);
@@ -793,8 +604,7 @@ public class EventBus extends BroadcastReceiver {
if (DEBUG_TRACE_ALL) {
logWithPid(" * Method: " + m.getName() +
- " event: " + parameterTypes[0].getSimpleName() +
- " interprocess? " + isInterprocessEvent.value);
+ " event: " + parameterTypes[0].getSimpleName());
}
}
}
@@ -830,12 +640,7 @@ public class EventBus extends BroadcastReceiver {
final EventHandler eventHandler = eventHandlers.get(i);
if (eventHandler.subscriber.getReference() != null) {
if (event.requiresPost) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- processEvent(eventHandler, event);
- }
- });
+ mHandler.post(() -> processEvent(eventHandler, event));
hasPostedEvent = true;
} else {
processEvent(eventHandler, event);
@@ -845,12 +650,7 @@ public class EventBus extends BroadcastReceiver {
// Clean up after this event, deferring until all subscribers have been called
if (hasPostedEvent) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- event.onPostDispatch();
- }
- });
+ mHandler.post(event::onPostDispatch);
} else {
event.onPostDispatch();
}
@@ -898,29 +698,6 @@ public class EventBus extends BroadcastReceiver {
}
/**
- * Re-registers the broadcast receiver for any new messages that we want to listen for.
- */
- private void registerReceiverForInterprocessEvents(Context context) {
- if (DEBUG_TRACE_ALL) {
- logWithPid("registerReceiverForInterprocessEvents()");
- }
- // Rebuild the receiver filter with the new interprocess events
- IntentFilter filter = new IntentFilter();
- for (String eventName : mInterprocessEventNameMap.keySet()) {
- filter.addAction(eventName);
- if (DEBUG_TRACE_ALL) {
- logWithPid(" filter: " + eventName);
- }
- }
- // Re-register the receiver with the new filter
- if (mHasRegisteredReceiver) {
- context.unregisterReceiver(this);
- }
- context.registerReceiverAsUser(this, UserHandle.ALL, filter, PERMISSION_SELF, mHandler);
- mHasRegisteredReceiver = true;
- }
-
- /**
* Returns whether this subscriber is currently registered. If {@param removeFoundSubscriber}
* is true, then remove the subscriber before returning.
*/
@@ -940,28 +717,19 @@ public class EventBus extends BroadcastReceiver {
/**
* @return whether {@param method} is a valid (normal or interprocess) event bus handler method
*/
- private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes,
- MutableBoolean isInterprocessEventOut) {
+ private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes) {
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers) &&
Modifier.isFinal(modifiers) &&
method.getReturnType().equals(Void.TYPE) &&
parameterTypes.length == 1) {
- if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) &&
- method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) {
- isInterprocessEventOut.value = true;
- return true;
- } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
+ if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
method.getName().startsWith(METHOD_PREFIX)) {
- isInterprocessEventOut.value = false;
return true;
} else {
if (DEBUG_TRACE_ALL) {
if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) {
logWithPid(" Expected method take an Event-based parameter: " + method.getName());
- } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) &&
- !method.getName().startsWith(METHOD_PREFIX)) {
- logWithPid(" Expected method start with method prefix: " + method.getName());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
index f204c42a6324..5ad2ba9d6f5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
@@ -14,7 +14,10 @@
* limitations under the License
*/
-package java.lang.annotation;
+package com.android.systemui.statusbar.notification;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE)
public @interface ShadeViewRefactor {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 52844fe0a54a..a725a0b5935c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -115,6 +115,8 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
@@ -134,8 +136,6 @@ import com.android.systemui.statusbar.policy.ScrollAdapter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.ShadeViewRefactor;
-import java.lang.annotation.ShadeViewRefactor.RefactorComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 235ff2bc93a6..c32dcea1f646 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -67,6 +67,10 @@ public class BarTransitions {
mView.setBackground(mBarBackground);
}
+ public void destroy() {
+ // To be overridden
+ }
+
public int getMode() {
return mMode;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 81b596c0345e..424acfd9916b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -34,9 +34,11 @@ class ConfigurationControllerImpl(context: Context)
private val inCarMode: Boolean
private var uiMode: Int = 0
private var localeList: LocaleList? = null
+ private val context: Context
init {
val currentConfig = context.resources.configuration
+ this.context = context
fontScale = currentConfig.fontScale
density = currentConfig.densityDpi
inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
@@ -82,6 +84,10 @@ class ConfigurationControllerImpl(context: Context)
}
if (uiModeChanged) {
+ // We need to force the style re-evaluation to make sure that it's up to date
+ // and attrs were reloaded.
+ context.theme.applyStyle(context.themeResId, true)
+
this.uiMode = uiMode
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onUiModeChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 10b019d5ddcd..66486cedcfb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -307,7 +307,10 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
@Override
public void onDestroyView() {
super.onDestroyView();
- mNavigationBarView.getLightTransitionsController().destroy(getContext());
+ if (mNavigationBarView != null) {
+ mNavigationBarView.getBarTransitions().destroy();
+ mNavigationBarView.getLightTransitionsController().destroy(getContext());
+ }
mOverviewProxyService.removeCallback(mOverviewProxyListener);
getContext().unregisterReceiver(mBroadcastReceiver);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index e09d31cea082..d58b5543221e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -44,6 +44,17 @@ public final class NavigationBarTransitions extends BarTransitions {
private boolean mAutoDim;
private View mNavButtons;
+ private final Handler mHandler = Handler.getMain();
+ private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
+ new IWallpaperVisibilityListener.Stub() {
+ @Override
+ public void onWallpaperVisibilityChanged(boolean newVisibility,
+ int displayId) throws RemoteException {
+ mWallpaperVisible = newVisibility;
+ mHandler.post(() -> applyLightsOut(true, false));
+ }
+ };
+
public NavigationBarTransitions(NavigationBarView view) {
super(view, R.drawable.nav_background);
mView = view;
@@ -55,17 +66,9 @@ public final class NavigationBarTransitions extends BarTransitions {
.getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
- Handler handler = Handler.getMain();
try {
mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener(
- new IWallpaperVisibilityListener.Stub() {
- @Override
- public void onWallpaperVisibilityChanged(boolean newVisibility,
- int displayId) throws RemoteException {
- mWallpaperVisible = newVisibility;
- handler.post(() -> applyLightsOut(true, false));
- }
- }, Display.DEFAULT_DISPLAY);
+ mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY);
} catch (RemoteException e) {
}
mView.addOnLayoutChangeListener(
@@ -88,6 +91,16 @@ public final class NavigationBarTransitions extends BarTransitions {
}
@Override
+ public void destroy() {
+ IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
+ try {
+ windowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
+ Display.DEFAULT_DISPLAY);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
public void setAutoDim(boolean autoDim) {
if (mAutoDim == autoDim) return;
mAutoDim = autoDim;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 21410160c5bf..9d13ea22b281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -615,6 +615,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
getImeSwitchButton().setImageDrawable(mImeIcon);
+ updateContextualContainerVisibility();
// Update menu button, visibility logic in method
setMenuVisibility(mShowMenu, true);
@@ -796,6 +797,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
+ updateContextualContainerVisibility();
}
public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
@@ -810,6 +812,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getAccessibilityButton().setLongClickable(longClickable);
+ updateContextualContainerVisibility();
}
public void updateRotateSuggestionButtonStyle(@StyleRes int style, boolean setIcon) {
@@ -839,6 +842,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getRotateSuggestionButton().setVisibility(vis);
mShowRotateButton = visible;
+ updateContextualContainerVisibility();
// Stop any active animations if hidden
if (!visible && mRotateSuggestionIcon.canAnimate()) {
@@ -855,6 +859,13 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
public boolean isRotateButtonVisible() { return mShowRotateButton; }
+ private void updateContextualContainerVisibility() {
+ // Only show the menu container when one of its buttons are visible
+ getMenuContainer().setVisibility((mShowAccessibilityButton || mShowRotateButton || mShowMenu
+ || (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0)
+ ? VISIBLE : INVISIBLE);
+ }
+
void hideRecentsOnboarding() {
mRecentsOnboarding.hide(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
index 7b9ed88b8b44..09833d44915d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -98,7 +98,6 @@ public class NearestTouchFrame extends FrameLayout {
return mClickableChildren
.stream()
.filter(v -> v.isAttachedToWindow())
- .filter(v -> v.isFocusable())
.map(v -> new Pair<>(distance(v, event), v))
.min(Comparator.comparingInt(f -> f.first))
.get().second;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index bd4d790a00b0..30e6afa8465f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -77,6 +77,8 @@ public class QuickStepController implements GestureHelper {
/** Experiment to swipe home button left to execute a back key press */
private static final String PULL_HOME_GO_BACK_PROP = "persist.quickstepcontroller.homegoesback";
private static final String HIDE_BACK_BUTTON_PROP = "persist.quickstepcontroller.hideback";
+ private static final String BACK_AFTER_END_PROP
+ = "persist.quickstepcontroller.homegoesbackwhenend";
private static final long BACK_BUTTON_FADE_OUT_ALPHA = 60;
private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
private static final long BACK_GESTURE_POLL_TIMEOUT = 1000;
@@ -84,9 +86,6 @@ public class QuickStepController implements GestureHelper {
/** When the home-swipe-back gesture is disallowed, make it harder to pull */
private static final float DISALLOW_GESTURE_DAMPING_FACTOR = 0.16f;
- /** When dragging the home button too far during back gesture, make it harder to pull */
- private static final float EXCEED_DRAG_HOME_DAMPING_FACTOR = 0.33f;
-
private NavigationBarView mNavigationBarView;
private boolean mQuickScrubActive;
@@ -361,7 +360,7 @@ public class QuickStepController implements GestureHelper {
// Once the user drags the home button past a certain limit, the distance
// will lessen as the home button dampens showing that it was pulled too far
float distanceAfterDragLimit = (Math.abs(diff) - mHomeBackGestureDragLimit)
- * EXCEED_DRAG_HOME_DAMPING_FACTOR;
+ * DISALLOW_GESTURE_DAMPING_FACTOR;
diff = (int)(distanceAfterDragLimit + mHomeBackGestureDragLimit);
if (mDragPositive) {
diff *= -1;
@@ -580,15 +579,21 @@ public class QuickStepController implements GestureHelper {
if (!mBackGestureActive) {
mBackGestureActive = true;
mNavigationBarView.getHomeButton().abortCurrentGesture();
+ final boolean runBackMidGesture
+ = !SystemProperties.getBoolean(BACK_AFTER_END_PROP, false);
if (mCanPerformBack) {
if (!shouldhideBackButton()) {
mNavigationBarView.getBackButton().setAlpha(0 /* alpha */, true /* animate */,
BACK_BUTTON_FADE_OUT_ALPHA);
}
- performBack();
+ if (runBackMidGesture) {
+ performBack();
+ }
}
mHandler.removeCallbacks(mExecuteBackRunnable);
- mHandler.postDelayed(mExecuteBackRunnable, BACK_GESTURE_POLL_TIMEOUT);
+ if (runBackMidGesture) {
+ mHandler.postDelayed(mExecuteBackRunnable, BACK_GESTURE_POLL_TIMEOUT);
+ }
}
}
@@ -609,6 +614,9 @@ public class QuickStepController implements GestureHelper {
mNavigationBarView.getBackButton().setAlpha(
mOverviewEventSender.getBackButtonAlpha(), true /* animate */);
}
+ if (SystemProperties.getBoolean(BACK_AFTER_END_PROP, false)) {
+ performBack();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7316c02dd226..459b4d721b70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1144,11 +1144,6 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onUiModeChanged() {
- // UiMode will change the style was already evaluated.
- // We need to force the re-evaluation to make sure that all parents
- // are up to date and new attrs will be rettrieved.
- mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
-
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onUiModeChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 167bba60b390..51a5df2730ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -135,6 +135,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
+ onThemeChanged();
}
public void setDozeScreenBrightness(int value) {
@@ -483,6 +484,10 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
@Override
public void onThemeChanged() {
+ if (mStatusBarView == null) {
+ return;
+ }
+
StatusBarStateController state = Dependency.get(StatusBarStateController.class);
int which;
if (state.getState() == StatusBarState.KEYGUARD
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index ce0bd58064fb..1e3d42ba6ede 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
@@ -316,7 +317,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
private void setBarStateForTest(int state) {
ArgumentCaptor<StatusBarStateController.StateListener> captor =
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
- verify(mBarState).addListener(captor.capture());
+ verify(mBarState, atLeastOnce()).addListener(captor.capture());
captor.getValue().onStateChanged(state);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
index 2423e148bb97..667a5082892d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
@@ -171,23 +171,6 @@ public class NearestTouchFrameTest extends SysuiTestCase {
ev.recycle();
}
- @Test
- public void testFurtherSelectedWhenCloserNotFocusable() {
- View closer = mockViewAt(0, 0, 10, 10);
- View further = mockViewAt(20, 0, 10, 10);
- closer.setFocusable(false);
-
- mNearestTouchFrame.addView(closer);
- mNearestTouchFrame.addView(further);
- mNearestTouchFrame.onMeasure(0, 0);
-
- MotionEvent ev = MotionEvent.obtain(0, 0, 0,
- 12 /* x */, 5 /* y */, 0);
- mNearestTouchFrame.onTouchEvent(ev);
- verify(further).onTouchEvent(eq(ev));
- ev.recycle();
- }
-
private View mockViewAt(int x, int y, int width, int height) {
View v = spy(new View(mContext));
doAnswer(invocation -> {
@@ -204,7 +187,6 @@ public class NearestTouchFrameTest extends SysuiTestCase {
v.setRight(width);
v.setTop(0);
v.setBottom(height);
- v.setFocusable(true);
return v;
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index f8223f61edb4..f7a7e0430977 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -83,4 +84,16 @@ public class StatusBarWindowControllerTest extends SysuiTestCase {
& WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
assertThat(flag).isEqualTo(0);
}
+
+ @Test
+ public void testOnThemeChanged_doesntCrash() {
+ mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
+ mActivityManager, mDozeParameters);
+ mStatusBarWindowController.onThemeChanged();
+ }
+
+ @Test
+ public void testAdd_updatesVisibilityFlags() {
+ verify(mStatusBarView).setSystemUiVisibility(anyInt());
+ }
}
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 51d95a2c1a58..872261a035e5 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -202,6 +202,15 @@ public class BinderCallsStatsService extends Binder {
reset();
pw.println("binder_calls_stats reset.");
return;
+ } else if ("--enable".equals(arg)) {
+ Binder.setObserver(mBinderCallsStats);
+ return;
+ } else if ("--disable".equals(arg)) {
+ Binder.setObserver(null);
+ return;
+ } else if ("--no-sampling".equals(arg)) {
+ mBinderCallsStats.setSamplingInterval(1);
+ return;
} else if ("--enable-detailed-tracking".equals(arg)) {
SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1");
mBinderCallsStats.setDetailedTracking(true);
@@ -215,6 +224,9 @@ public class BinderCallsStatsService extends Binder {
} else if ("-h".equals(arg)) {
pw.println("binder_calls_stats commands:");
pw.println(" --reset: Reset stats");
+ pw.println(" --enable: Enable tracking binder calls");
+ pw.println(" --disable: Disables tracking binder calls");
+ pw.println(" --no-sampling: Tracks all calls");
pw.println(" --enable-detailed-tracking: Enables detailed tracking");
pw.println(" --disable-detailed-tracking: Disables detailed tracking");
return;
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index ab7bf288a2ff..ee01d8633ae7 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -189,6 +189,10 @@ public class LooperStatsService extends Binder {
} else if ("reset".equals(cmd)) {
mStats.reset();
return 0;
+ } else if ("sampling_interval".equals(cmd)) {
+ int sampling = Integer.parseUnsignedInt(getNextArgRequired());
+ setSamplingInterval(sampling);
+ return 0;
} else {
return handleDefaultCommands(cmd);
}
@@ -198,9 +202,10 @@ public class LooperStatsService extends Binder {
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
pw.println(LOOPER_STATS_SERVICE_NAME + " commands:");
- pw.println(" enable: Enable collecting stats");
- pw.println(" disable: Disable collecting stats");
- pw.println(" reset: Reset stats");
+ pw.println(" enable: Enable collecting stats.");
+ pw.println(" disable: Disable collecting stats.");
+ pw.println(" sampling_interval: Change the sampling interval.");
+ pw.println(" reset: Reset stats.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 1866420f2a81..01421c7e65c2 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -126,11 +126,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
- @VisibleForTesting
- ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
- this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
- }
-
ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
mSupervisor = supervisor;
mDisplayId = display.getDisplayId();
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index eb41fe7323ac..bcb2b9b9ddfd 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -52,6 +52,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -1901,14 +1902,20 @@ class ActivityStarter {
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
// the same behavior as if a new instance was being started, which means not bringing it
// to the front if the caller is not itself in the front.
- final ActivityStack focusStack = mSupervisor.getTopDisplayFocusedStack();
- ActivityRecord curTop = (focusStack == null)
- ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
-
- final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
- if (topTask != null
- && (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
- && !mAvoidMoveToFront) {
+ final boolean differentTopTask;
+ if (mPreferredDisplayId == mTargetStack.mDisplayId) {
+ final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
+ final ActivityRecord curTop = (focusStack == null)
+ ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+ final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
+ differentTopTask = topTask != null
+ && (topTask != intentActivity.getTask() || topTask != focusStack.topTask());
+ } else {
+ // The existing task should always be different from those in other displays.
+ differentTopTask = true;
+ }
+
+ if (differentTopTask && !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
mSourceStack.getTopActivity().getTask() == mSourceRecord.getTask())) {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 36e7cba9c818..6b09f1bab364 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -39,12 +39,17 @@ public abstract class AuthenticationClient extends ClientMonitor {
public abstract int handleFailedAttempt();
public abstract void resetFailedAttempts();
+ public abstract String getErrorString(int error, int vendorCode);
+ public abstract String getAcquiredString(int acquireInfo, int vendorCode);
+ /**
+ * @return one of {@link #TYPE_FINGERPRINT} {@link #TYPE_IRIS} or {@link #TYPE_FACE}
+ */
+ public abstract int getBiometricType();
public static final int LOCKOUT_NONE = 0;
public static final int LOCKOUT_TIMED = 1;
public static final int LOCKOUT_PERMANENT = 2;
- private final BiometricAuthenticator mAuthenticator;
// Callback mechanism received from the client
// (BiometricPrompt -> BiometricPromptService -> <Biometric>Service -> AuthenticationClient)
private IBiometricPromptReceiver mDialogReceiverFromClient;
@@ -88,15 +93,13 @@ public abstract class AuthenticationClient extends ClientMonitor {
BiometricService.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricService.ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
- BiometricAuthenticator authenticator) {
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
super(context, metrics, daemon, halDeviceId, token, listener, targetUserId, groupId,
restricted, owner);
mOpId = opId;
mBundle = bundle;
mDialogReceiverFromClient = dialogReceiver;
mStatusBarService = statusBarService;
- mAuthenticator = authenticator;
mHandler = new Handler(Looper.getMainLooper());
}
@@ -115,8 +118,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
if (mBundle != null) {
try {
if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
- mStatusBarService.onBiometricHelp(
- mAuthenticator.getAcquiredString(acquiredInfo, vendorCode));
+ mStatusBarService.onBiometricHelp(getAcquiredString(acquiredInfo, vendorCode));
}
return false; // acquisition continues
} catch (RemoteException e) {
@@ -144,8 +146,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
if (mBundle != null) {
try {
- mStatusBarService.onBiometricError(
- mAuthenticator.getErrorString(error, vendorCode));
+ mStatusBarService.onBiometricError(getErrorString(error, vendorCode));
} catch (RemoteException e) {
Slog.e(getLogTag(), "Remote exception when sending error", e);
}
@@ -220,7 +221,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
// Send the lockout message to the system dialog
if (mBundle != null) {
mStatusBarService.onBiometricError(
- mAuthenticator.getErrorString(errorCode, 0 /* vendorCode */));
+ getErrorString(errorCode, 0 /* vendorCode */));
mHandler.postDelayed(() -> {
try {
listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
@@ -268,7 +269,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
if (mBundle != null) {
try {
mStatusBarService.showBiometricDialog(mBundle, mDialogReceiver,
- mAuthenticator.getType());
+ getBiometricType());
} catch (RemoteException e) {
Slog.e(getLogTag(), "Unable to show biometric dialog", e);
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a181b6105471..73c4223b48f8 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -108,6 +108,8 @@ public abstract class BiometricService extends SystemService implements IHwBinde
private ClientMonitor mPendingClient;
private PerformanceStats mPerformanceStats;
protected int mCurrentUserId = UserHandle.USER_NULL;
+ // Tracks if the current authentication makes use of CryptoObjects.
+ protected boolean mIsCrypto;
// Normal authentications are tracked by mPerformanceMap.
protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
// Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
@@ -217,16 +219,16 @@ public abstract class BiometricService extends SystemService implements IHwBinde
*/
protected void notifyClientActiveCallbacks(boolean isActive) {}
- protected class AuthenticationClientImpl extends AuthenticationClient {
+ protected abstract class AuthenticationClientImpl extends AuthenticationClient {
public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
IBiometricPromptReceiver dialogReceiver,
- IStatusBarService statusBarService, BiometricAuthenticator authenticator) {
+ IStatusBarService statusBarService) {
super(context, getMetrics(), daemon, halDeviceId, token, listener,
targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
- statusBarService, authenticator);
+ statusBarService);
}
@Override
@@ -715,6 +717,7 @@ public abstract class BiometricService extends SystemService implements IHwBinde
pmap.put(mCurrentUserId, stats);
}
mPerformanceStats = stats;
+ mIsCrypto = (opId != 0);
startAuthentication(client, opPackageName);
});
@@ -847,7 +850,7 @@ public abstract class BiometricService extends SystemService implements IHwBinde
return mKeyguardPackage.equals(clientPackage);
}
- private int getLockoutMode() {
+ protected int getLockoutMode() {
final int currentUser = ActivityManager.getCurrentUser();
final int failedAttempts = mFailedAttempts.get(currentUser, 0);
if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
@@ -1109,4 +1112,4 @@ public abstract class BiometricService extends SystemService implements IHwBinde
LockoutResetMonitor monitor) {
mLockoutMonitors.remove(monitor);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 8afac97f647f..660710e34947 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -49,6 +49,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.biometrics.BiometricService;
@@ -82,6 +83,33 @@ public class FaceService extends BiometricService {
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 3;
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 12;
+ private final class FaceAuthClient extends AuthenticationClientImpl {
+ public FaceAuthClient(Context context,
+ DaemonWrapper daemon, long halDeviceId, IBinder token,
+ ServiceListener listener, int targetUserId, int groupId, long opId,
+ boolean restricted, String owner, Bundle bundle,
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
+ super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
+ restricted,
+ owner, bundle, dialogReceiver, statusBarService);
+ }
+
+ @Override
+ public String getErrorString(int error, int vendorCode) {
+ return FaceManager.getErrorString(getContext(), error, vendorCode);
+ }
+
+ @Override
+ public String getAcquiredString(int acquireInfo, int vendorCode) {
+ return FaceManager.getAcquiredString(getContext(), acquireInfo, vendorCode);
+ }
+
+ @Override
+ public int getBiometricType() {
+ return BiometricAuthenticator.TYPE_FACE;
+ }
+ }
+
/**
* Receives the incoming binder calls from FaceManager.
*/
@@ -128,10 +156,10 @@ public class FaceService extends BiometricService {
final String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
final boolean restricted = isRestricted();
- final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
- null /* bundle */, null /* dialogReceiver */, mStatusBarService, mFaceManager);
+ null /* bundle */, null /* dialogReceiver */, mStatusBarService);
authenticateInternal(client, opId, opPackageName);
}
@@ -143,11 +171,11 @@ public class FaceService extends BiometricService {
int callingUid, int callingPid, int callingUserId) {
checkPermission(USE_BIOMETRIC_INTERNAL);
final boolean restricted = true; // BiometricPrompt is always restricted
- final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(receiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
- bundle, dialogReceiver, mStatusBarService, mFaceManager);
+ bundle, dialogReceiver, mStatusBarService);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -338,8 +366,8 @@ public class FaceService extends BiometricService {
*/
if (mBiometricPromptServiceReceiver != null) {
mBiometricPromptServiceReceiver.onAcquired(deviceId,
- mFaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
- mFaceManager.getAcquiredString(acquiredInfo, vendorCode));
+ FaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
+ FaceManager.getAcquiredString(getContext(), acquiredInfo, vendorCode));
}
}
@@ -362,7 +390,7 @@ public class FaceService extends BiometricService {
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
if (mBiometricPromptServiceReceiver != null) {
mBiometricPromptServiceReceiver.onError(deviceId, error,
- mFaceManager.getErrorString(error, vendorCode));
+ FaceManager.getErrorString(getContext(), error, vendorCode));
}
}
}
@@ -447,8 +475,6 @@ public class FaceService extends BiometricService {
@GuardedBy("this")
private IBiometricsFace mDaemon;
private long mHalDeviceId;
- // Use FaceManager to get strings, so BiometricPrompt interface is cleaner
- private FaceManager mFaceManager;
/**
* Receives callbacks from the HAL.
@@ -589,7 +615,6 @@ public class FaceService extends BiometricService {
super.onStart();
publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
SystemServerInitThreadPool.get().submit(this::getFaceDaemon, TAG + ".onStart");
- mFaceManager = (FaceManager) getContext().getSystemService(Context.FACE_SERVICE);
}
@Override
@@ -862,4 +887,4 @@ public class FaceService extends BiometricService {
mPerformanceMap.clear();
mCryptoPerformanceMap.clear();
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 95fb9e33dded..9f4fff8157a2 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -50,12 +50,15 @@ import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
+import android.util.StatsLog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
+import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricService;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.ClientMonitor;
@@ -102,6 +105,33 @@ public class FingerprintService extends BiometricService {
}
}
+ private final class FingerprintAuthClient extends AuthenticationClientImpl {
+ public FingerprintAuthClient(Context context,
+ DaemonWrapper daemon, long halDeviceId, IBinder token,
+ ServiceListener listener, int targetUserId, int groupId, long opId,
+ boolean restricted, String owner, Bundle bundle,
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
+ super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
+ restricted,
+ owner, bundle, dialogReceiver, statusBarService);
+ }
+
+ @Override
+ public String getErrorString(int error, int vendorCode) {
+ return FingerprintManager.getErrorString(getContext(), error, vendorCode);
+ }
+
+ @Override
+ public String getAcquiredString(int acquireInfo, int vendorCode) {
+ return FingerprintManager.getAcquiredString(getContext(), acquireInfo, vendorCode);
+ }
+
+ @Override
+ public int getBiometricType() {
+ return BiometricAuthenticator.TYPE_FINGERPRINT;
+ }
+ }
+
/**
* Receives the incoming binder calls from FingerprintManager.
*/
@@ -149,10 +179,10 @@ public class FingerprintService extends BiometricService {
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
final boolean restricted = isRestricted();
- final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, groupId, opId, restricted, opPackageName, null /* bundle */,
- null /* dialogReceiver */, mStatusBarService, mFingerprintManager);
+ null /* dialogReceiver */, mStatusBarService);
authenticateInternal(client, opId, opPackageName);
}
@@ -164,11 +194,11 @@ public class FingerprintService extends BiometricService {
int callingUid, int callingPid, int callingUserId) {
checkPermission(MANAGE_BIOMETRIC);
final boolean restricted = true; // BiometricPrompt is always restricted
- final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+ final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(receiver),
mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
- dialogReceiver, mStatusBarService, mFingerprintManager);
+ dialogReceiver, mStatusBarService);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -371,7 +401,8 @@ public class FingerprintService extends BiometricService {
throws RemoteException {
if (mBiometricPromptServiceReceiver != null) {
mBiometricPromptServiceReceiver.onAcquired(deviceId, acquiredInfo,
- mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
+ FingerprintManager.getAcquiredString(
+ getContext(), acquiredInfo, vendorCode));
}
}
@@ -394,7 +425,7 @@ public class FingerprintService extends BiometricService {
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
if (mBiometricPromptServiceReceiver != null) {
mBiometricPromptServiceReceiver.onError(deviceId, error,
- mFingerprintManager.getErrorString(error, vendorCode));
+ FingerprintManager.getErrorString(getContext(), error, vendorCode));
}
}
}
@@ -567,8 +598,6 @@ public class FingerprintService extends BiometricService {
private long mHalDeviceId;
private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
- // Use FingerprintManager to get strings, so BiometricPrompt interface is cleaner.
- private FingerprintManager mFingerprintManager;
/**
* Receives callbacks from the HAL.
@@ -590,6 +619,11 @@ public class FingerprintService extends BiometricService {
public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
mHandler.post(() -> {
FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
+ if (getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
+ && getCurrentClient() instanceof AuthenticationClient) {
+ // Ignore enrollment acquisitions or acquisitions when we are locked out.
+ StatsLog.write(StatsLog.FINGERPRINT_ACQUIRED, mCurrentUserId, mIsCrypto);
+ }
});
}
@@ -599,6 +633,22 @@ public class FingerprintService extends BiometricService {
mHandler.post(() -> {
Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
FingerprintService.super.handleAuthenticated(fp, token);
+ // Send authentication to statsd.
+ final boolean authenticated = fingerId != 0;
+ StatsLog.write(StatsLog.FINGERPRINT_AUTHENTICATED, mCurrentUserId, mIsCrypto,
+ authenticated);
+ if (!authenticated) {
+ // If we failed to authenticate because of a lockout, inform statsd.
+ final int lockoutMode = getLockoutMode();
+ if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
+ StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
+ mIsCrypto, StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__LOCKOUT);
+ } else if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+ StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
+ mIsCrypto,
+ StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__PERMANENT_LOCKOUT);
+ }
+ }
});
}
@@ -717,8 +767,6 @@ public class FingerprintService extends BiometricService {
super.onStart();
publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
- mFingerprintManager = (FingerprintManager)
- getContext().getSystemService(Context.FINGERPRINT_SERVICE);
}
@Override
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 050a075dd993..d326c229d6de 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -20,6 +20,7 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.Context.DEVICE_POLICY_SERVICE;
+import static android.os.UserHandle.USER_ALL;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -53,12 +54,15 @@ import android.service.notification.ManagedServicesProto.ServiceProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -72,6 +76,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
@@ -138,10 +143,6 @@ abstract public class ManagedServices {
// not mean that we are currently bound to said package/component.
private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
- // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
- // user change).
- private int[] mLastSeenProfileIds;
-
// True if approved services are stored in xml, not settings.
private boolean mUseXml;
@@ -300,7 +301,7 @@ abstract public class ManagedServices {
Settings.Secure.putStringForUser(
mContext.getContentResolver(), element, value, userId);
loadAllowedComponentsFromSettings();
- rebindServices(false);
+ rebindServices(false, userId);
}
}
}
@@ -385,7 +386,7 @@ abstract public class ManagedServices {
}
}
}
- rebindServices(false);
+ rebindServices(false, USER_ALL);
}
protected void upgradeXml(final int xmlVersion, final int userId) {}
@@ -460,7 +461,7 @@ abstract public class ManagedServices {
}
}
- rebindServices(false);
+ rebindServices(false, userId);
}
private String getApprovedValue(String pkgOrComponent) {
@@ -578,7 +579,7 @@ abstract public class ManagedServices {
if (anyServicesInvolved) {
// make sure we're still bound to any of our services who may have just upgraded
- rebindServices(false);
+ rebindServices(false, USER_ALL);
}
}
}
@@ -586,21 +587,17 @@ abstract public class ManagedServices {
public void onUserRemoved(int user) {
Slog.i(TAG, "Removing approved services for removed user " + user);
mApproved.remove(user);
- rebindServices(true);
+ rebindServices(true, user);
}
public void onUserSwitched(int user) {
if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
- if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
- if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
- return;
- }
- rebindServices(true);
+ rebindServices(true, user);
}
public void onUserUnlocked(int user) {
if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
- rebindServices(false);
+ rebindServices(false, user);
}
private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
@@ -694,9 +691,10 @@ abstract public class ManagedServices {
component.flattenToShortString());
synchronized (mMutex) {
- final int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final IntArray userIds = mUserProfiles.getCurrentProfileIds();
- for (int userId : userIds) {
+ for (int i = 0; i < userIds.size(); i++) {
+ final int userId = userIds.get(i);
if (enabled) {
if (isPackageOrComponentAllowed(component.toString(), userId)
|| isPackageOrComponentAllowed(component.getPackageName(), userId)) {
@@ -838,20 +836,14 @@ abstract public class ManagedServices {
return false;
}
- /**
- * Called whenever packages change, the user switches, or the secure setting
- * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
- */
- protected void rebindServices(boolean forceRebind) {
- if (DEBUG) Slog.d(TAG, "rebindServices");
- final int[] userIds = mUserProfiles.getCurrentProfileIds();
- final int nUserIds = userIds.length;
-
+ @VisibleForTesting
+ protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
+ final int nUserIds = userIds.size();
final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
for (int i = 0; i < nUserIds; ++i) {
- final int userId = userIds[i];
- final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userIds[i]);
+ final int userId = userIds.get(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
if (approvedLists != null) {
final int N = approvedLists.size();
for (int j = 0; j < N; j++) {
@@ -865,67 +857,125 @@ abstract public class ManagedServices {
}
}
}
+ return componentsByUser;
+ }
- final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
- final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
+ @GuardedBy("mMutex")
+ protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
+ final IntArray activeUsers,
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
+ mEnabledServicesForCurrentProfiles.clear();
+ mEnabledServicesPackageNames.clear();
+ final int nUserIds = activeUsers.size();
- synchronized (mMutex) {
- // Rebind to non-system services if user switched
- for (ManagedServiceInfo service : mServices) {
- if (!service.isSystem && !service.isGuest(this)) {
- removableBoundServices.add(service);
- }
+ for (int i = 0; i < nUserIds; ++i) {
+ // decode the list of components
+ final int userId = activeUsers.get(i);
+ final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
+ if (null == userComponents) {
+ componentsToBind.put(userId, new ArraySet<>());
+ continue;
}
- mEnabledServicesForCurrentProfiles.clear();
- mEnabledServicesPackageNames.clear();
+ final Set<ComponentName> add = new HashSet<>(userComponents);
+ add.removeAll(mSnoozingForCurrentProfiles);
- for (int i = 0; i < nUserIds; ++i) {
- // decode the list of components
- final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
- if (null == userComponents) {
- toAdd.put(userIds[i], new ArraySet<>());
- continue;
- }
-
- final Set<ComponentName> add = new HashSet<>(userComponents);
- add.removeAll(mSnoozingForCurrentProfiles);
+ componentsToBind.put(userId, add);
- toAdd.put(userIds[i], add);
+ mEnabledServicesForCurrentProfiles.addAll(userComponents);
- mEnabledServicesForCurrentProfiles.addAll(userComponents);
+ for (int j = 0; j < userComponents.size(); j++) {
+ final ComponentName component = userComponents.valueAt(j);
+ mEnabledServicesPackageNames.add(component.getPackageName());
+ }
+ }
+ }
- for (int j = 0; j < userComponents.size(); j++) {
- final ComponentName component = userComponents.valueAt(j);
- mEnabledServicesPackageNames.add(component.getPackageName());
- }
+ @GuardedBy("mMutex")
+ protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
+ final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+ for (ManagedServiceInfo service : mServices) {
+ if (!service.isSystem && !service.isGuest(this)) {
+ removableBoundServices.add(service);
}
}
+ return removableBoundServices;
+ }
+ protected void populateComponentsToUnbind(
+ boolean forceRebind,
+ Set<ManagedServiceInfo> removableBoundServices,
+ SparseArray<Set<ComponentName>> allowedComponentsToBind,
+ SparseArray<Set<ComponentName>> componentsToUnbind) {
for (ManagedServiceInfo info : removableBoundServices) {
- final ComponentName component = info.component;
- final int oldUser = info.userid;
- final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
+ final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
if (allowedComponents != null) {
- if (allowedComponents.contains(component) && !forceRebind) {
- // Already bound, don't need to bind again.
- allowedComponents.remove(component);
- } else {
- // No longer allowed to be bound, or must rebind.
- Slog.v(TAG, "disabling " + getCaption() + " for user "
- + oldUser + ": " + component);
- unregisterService(component, oldUser);
+ if (forceRebind || !allowedComponents.contains(info.component)) {
+ Set<ComponentName> toUnbind =
+ componentsToUnbind.get(info.userid, new ArraySet<>());
+ toUnbind.add(info.component);
+ componentsToUnbind.put(info.userid, toUnbind);
}
}
}
+ }
- for (int i = 0; i < nUserIds; ++i) {
- final Set<ComponentName> add = toAdd.get(userIds[i]);
+ /**
+ * Called whenever packages change, the user switches, or the secure setting
+ * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+ */
+ protected void rebindServices(boolean forceRebind, int userToRebind) {
+ if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
+ IntArray userIds = mUserProfiles.getCurrentProfileIds();
+ if (userToRebind != USER_ALL) {
+ userIds = new IntArray(1);
+ userIds.add(userToRebind);
+ }
+
+ final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+ final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+ synchronized (mMutex) {
+ final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
+ getAllowedComponents(userIds);
+ final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
+
+ // Filter approvedComponentsByUser to collect all of the components that are allowed
+ // for the currently active user(s).
+ populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
+
+ // For every current non-system connection, disconnect services that are no longer
+ // approved, or ALL services if we are force rebinding
+ populateComponentsToUnbind(
+ forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
+ }
+
+ unbindFromServices(componentsToUnbind);
+ bindToServices(componentsToBind);
+ }
+
+ protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
+ for (int i = 0; i < componentsToUnbind.size(); i++) {
+ final int userId = componentsToUnbind.keyAt(i);
+ final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
+ for (ComponentName cn : removableComponents) {
+ // No longer allowed to be bound, or must rebind.
+ Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
+ unregisterService(cn, userId);
+ }
+ }
+ }
+
+ // Attempt to bind to services, skipping those that cannot be found or lack the permission.
+ private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
+ for (int i = 0; i < componentsToBind.size(); i++) {
+ final int userId = componentsToBind.keyAt(i);
+ final Set<ComponentName> add = componentsToBind.get(userId);
for (ComponentName component : add) {
try {
ServiceInfo info = mPm.getServiceInfo(component,
PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (info == null) {
Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ ": service not found");
@@ -937,15 +987,13 @@ abstract public class ManagedServices {
continue;
}
Slog.v(TAG,
- "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
- registerService(component, userIds[i]);
+ "enabling " + getCaption() + " for " + userId + ": " + component);
+ registerService(component, userId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
}
-
- mLastSeenProfileIds = userIds;
}
/**
@@ -1022,7 +1070,7 @@ abstract public class ManagedServices {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
- Slog.v(TAG, getCaption() + " service connected: " + name);
+ Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
boolean added = false;
ManagedServiceInfo info = null;
synchronized (mMutex) {
@@ -1044,12 +1092,12 @@ abstract public class ManagedServices {
@Override
public void onServiceDisconnected(ComponentName name) {
- Slog.v(TAG, getCaption() + " connection lost: " + name);
+ Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
}
@Override
public void onBindingDied(ComponentName name) {
- Slog.w(TAG, getCaption() + " binding died: " + name);
+ Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
synchronized (mMutex) {
unbindService(this, name, userid);
if (!mServicesRebinding.contains(servicesBindingTag)) {
@@ -1061,8 +1109,8 @@ abstract public class ManagedServices {
}
}, ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
- Slog.v(TAG, getCaption() + " not rebinding as "
- + "a previous rebind attempt was made: " + name);
+ Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+ + " as a previous rebind attempt was made: " + name);
}
}
}
@@ -1072,7 +1120,8 @@ abstract public class ManagedServices {
getBindFlags(),
new UserHandle(userid))) {
mServicesBound.remove(servicesBindingTag);
- Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
+ Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
+ + " in user " + userid);
return;
}
} catch (SecurityException ex) {
@@ -1236,9 +1285,9 @@ abstract public class ManagedServices {
if (!isEnabledForCurrentProfiles()) {
return false;
}
- if (this.userid == UserHandle.USER_ALL) return true;
+ if (this.userid == USER_ALL) return true;
if (this.isSystem) return true;
- if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
+ if (nid == USER_ALL || nid == this.userid) return true;
return supportsProfiles()
&& mUserProfiles.isCurrentProfile(nid)
&& isPermittedForProfile(nid);
@@ -1284,6 +1333,24 @@ abstract public class ManagedServices {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ManagedServiceInfo that = (ManagedServiceInfo) o;
+ return userid == that.userid
+ && isSystem == that.isSystem
+ && targetSdkVersion == that.targetSdkVersion
+ && Objects.equals(service, that.service)
+ && Objects.equals(component, that.component)
+ && Objects.equals(connection, that.connection);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
+ }
}
/** convenience method for looking in mEnabledServicesForCurrentProfiles */
@@ -1309,12 +1376,15 @@ abstract public class ManagedServices {
}
}
- public int[] getCurrentProfileIds() {
+ /**
+ * Returns the currently active users (generally one user and its work profile).
+ */
+ public IntArray getCurrentProfileIds() {
synchronized (mCurrentProfiles) {
- int[] users = new int[mCurrentProfiles.size()];
+ IntArray users = new IntArray(mCurrentProfiles.size());
final int N = mCurrentProfiles.size();
for (int i = 0; i < N; ++i) {
- users[i] = mCurrentProfiles.keyAt(i);
+ users.add(mCurrentProfiles.keyAt(i));
}
return users;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33f0172811ea..e53eeb07fbf2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -178,6 +178,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -1566,7 +1567,7 @@ public class NotificationManagerService extends SystemService {
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- getContext().registerReceiver(mIntentReceiver, filter);
+ getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -1698,10 +1699,10 @@ public class NotificationManagerService extends SystemService {
UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
null);
if (isUidSystemOrPhone(uid)) {
- int[] profileIds = mUserProfiles.getCurrentProfileIds();
- int N = profileIds.length;
+ IntArray profileIds = mUserProfiles.getCurrentProfileIds();
+ int N = profileIds.size();
for (int i = 0; i < N; i++) {
- int profileId = profileIds[i];
+ int profileId = profileIds.get(i);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
profileId, REASON_CHANNEL_BANNED,
null);
@@ -6691,7 +6692,9 @@ public class NotificationManagerService extends SystemService {
@Override
public void onUserUnlocked(int user) {
if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
- rebindServices(true);
+ // force rebind the assistant, as it might be keeping its own state in user locked
+ // storage
+ rebindServices(true, user);
}
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index a178a525cede..2b581d601ad5 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -15,17 +15,8 @@
*/
package com.android.server.notification;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import android.annotation.NonNull;
import android.app.AlarmManager;
-import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -37,9 +28,18 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -105,12 +105,12 @@ public class SnoozeHelper {
protected @NonNull List<NotificationRecord> getSnoozed() {
List<NotificationRecord> snoozedForUser = new ArrayList<>();
- int[] userIds = mUserProfiles.getCurrentProfileIds();
+ IntArray userIds = mUserProfiles.getCurrentProfileIds();
if (userIds != null) {
- final int N = userIds.length;
+ final int N = userIds.size();
for (int i = 0; i < N; i++) {
final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
- mSnoozedNotifications.get(userIds[i]);
+ mSnoozedNotifications.get(userIds.get(i));
if (snoozedPkgs != null) {
final int M = snoozedPkgs.size();
for (int j = 0; j < M; j++) {
@@ -179,7 +179,7 @@ public class SnoozeHelper {
protected boolean cancel(int userId, boolean includeCurrentProfiles) {
int[] userIds = {userId};
if (includeCurrentProfiles) {
- userIds = mUserProfiles.getCurrentProfileIds();
+ userIds = mUserProfiles.getCurrentProfileIds().toArray();
}
final int N = userIds.length;
for (int i = 0; i < N; i++) {
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 5bf323ac2239..560ca92f494d 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -378,7 +378,7 @@ public class ComponentResolver {
for (int i = newIntents.size() - 1; i >= 0; --i) {
final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
final PackageParser.Package disabledPkg = sPackageManagerInternal
- .getDisabledSystemPackage(intentInfo.activity.info.packageName);
+ .getDisabledPackage(intentInfo.activity.info.packageName);
final List<PackageParser.Activity> systemActivities =
disabledPkg != null ? disabledPkg.activities : null;
adjustPriority(systemActivities, intentInfo, setupWizardPackage);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bca3ca71a911..5810e309f236 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 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
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 class OtaDexoptService extends IOtaDexopt.Stub {
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 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
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 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
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 */,
@@ -445,24 +438,22 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
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 91af0eca8707..db0c13cbf7d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -718,8 +718,6 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
- private PackageManager mPackageManager;
-
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -22238,22 +22236,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isPlatformSigned(String packageName) {
- PackageSetting packageSetting = mSettings.mPackages.get(packageName);
- if (packageSetting == null) {
- return false;
- }
- PackageParser.Package pkg = packageSetting.pkg;
- if (pkg == null) {
- // May happen if package in on a removable sd card
- return false;
- }
- return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
- || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
- PackageParser.SigningDetails.CertCapabilities.PERMISSION);
- }
-
- @Override
public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
SigningDetails sd = getSigningDetails(packageName);
if (sd == null) {
@@ -22365,7 +22347,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public PackageParser.Package getDisabledSystemPackage(String packageName) {
+ public PackageParser.Package getDisabledPackage(String packageName) {
synchronized (mPackages) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
return (ps != null) ? ps.pkg : null;
@@ -22373,12 +22355,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
- PackageParser.Package pkg = getDisabledSystemPackage(packageName);
- return pkg == null ? null : pkg.packageName;
- }
-
- @Override
public String getKnownPackageName(int knownPackage, int userId) {
switch(knownPackage) {
case PackageManagerInternal.PACKAGE_BROWSER:
@@ -22416,6 +22392,21 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public void setSmsAppPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setSmsAppPackagesProvider(provider);
+ }
+
+ @Override
+ public void setDialerAppPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setDialerAppPackagesProvider(provider);
+ }
+
+ @Override
+ public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setSimCallManagerPackagesProvider(provider);
+ }
+
+ @Override
public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
}
@@ -22426,10 +22417,22 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void onDefaultDialerAppChanged(String packageName, int userId) {
+ public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsApp(packageName, userId);
+ }
+
+ @Override
+ public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
synchronized (mPackages) {
mSettings.setDefaultDialerPackageNameLPw(packageName, userId);
}
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerApp(packageName, userId);
+ }
+
+ @Override
+ public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+ packageName, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index d9eb7e8d729c..846c7b7a7e0c 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -23,13 +23,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.DownloadManager;
-import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
import android.companion.CompanionDeviceManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackagesProvider;
@@ -54,7 +53,6 @@ import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.Telephony.Sms.Intents;
import android.security.Credentials;
-import android.speech.RecognitionService;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -63,7 +61,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.Xml;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
@@ -76,7 +73,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -98,15 +94,10 @@ public final class DefaultPermissionGrantPolicy {
private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
private static final boolean DEBUG = false;
- @PackageManager.ResolveInfoFlags
- private static final int DEFAULT_INTENT_QUERY_FLAGS =
+ private static final int DEFAULT_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_UNINSTALLED_PACKAGES;
- @PackageManager.PackageInfoFlags
- private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS =
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS;
-
private static final String AUDIO_MIME_TYPE = "audio/mpeg";
private static final String TAG_EXCEPTIONS = "exceptions";
@@ -117,8 +108,6 @@ public final class DefaultPermissionGrantPolicy {
private static final String ATTR_FIXED = "fixed";
private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
-
-
static {
PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
@@ -230,7 +219,7 @@ public final class DefaultPermissionGrantPolicy {
private final DefaultPermissionGrantedCallback mPermissionGrantedCallback;
public interface DefaultPermissionGrantedCallback {
/** Callback when permissions have been granted */
- void onDefaultRuntimePermissionsGranted(int userId);
+ public void onDefaultRuntimePermissionsGranted(int userId);
}
public DefaultPermissionGrantPolicy(Context context, Looper looper,
@@ -302,9 +291,9 @@ public final class DefaultPermissionGrantPolicy {
grantDefaultPermissionExceptions(userId);
}
- private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
+ private void grantRuntimePermissionsForPackage(int userId, PackageParser.Package pkg) {
Set<String> permissions = new ArraySet<>();
- for (String permission : pkg.requestedPermissions) {
+ for (String permission : pkg.requestedPermissions) {
final BasePermission bp = mPermissionManager.getPermission(permission);
if (bp == null) {
continue;
@@ -318,71 +307,36 @@ public final class DefaultPermissionGrantPolicy {
}
}
+ private void grantAllRuntimePermissions(int userId) {
+ Log.i(TAG, "Granting all runtime permissions for user " + userId);
+ final PackageList packageList = mServiceInternal.getPackageList();
+ for (String packageName : packageList.getPackageNames()) {
+ final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
+ if (pkg == null) {
+ continue;
+ }
+ grantRuntimePermissionsForPackage(userId, pkg);
+ }
+ }
+
public void scheduleReadDefaultPermissionExceptions() {
mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
}
private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
Log.i(TAG, "Granting permissions to platform components for user " + userId);
- List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
- DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM);
- for (PackageInfo pkg : packages) {
+ final PackageList packageList = mServiceInternal.getPackageList();
+ for (String packageName : packageList.getPackageNames()) {
+ final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
if (pkg == null) {
continue;
}
if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
|| !doesPackageSupportRuntimePermissions(pkg)
- || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
+ || pkg.requestedPermissions.isEmpty()) {
continue;
}
- grantRuntimePermissionsForSystemPackage(userId, pkg);
- }
- }
-
- @SafeVarargs
- private final void grantIgnoringSystemPackage(String packageName, int userId,
- Set<String>... permissionGroups) {
- grantPermissionsToSystemPackage(packageName, userId, false, true, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId,
- Set<String>... permissionGroups) {
- grantPermissionsToSystemPackage(packageName, userId, true, false, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantPermissionsToSystemPackage(
- String packageName, int userId, Set<String>... permissionGroups) {
- grantPermissionsToSystemPackage(packageName, userId, false, false, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantPermissionsToSystemPackage(String packageName, int userId,
- boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
- if (!ignoreSystemPackage && !isSystemPackage(packageName)) {
- return;
- }
- grantRuntimePermissionsToPackage(getSystemPackageInfo(packageName),
- userId, systemFixed, ignoreSystemPackage, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantRuntimePermissionsToPackage(String packageName, int userId,
- boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
- grantRuntimePermissionsToPackage(getPackageInfo(packageName),
- userId, systemFixed, ignoreSystemPackage, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantRuntimePermissionsToPackage(PackageInfo packageName, int userId,
- boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
- if (packageName == null) return;
- if (doesPackageSupportRuntimePermissions(packageName)) {
- for (Set<String> permissionGroup : permissionGroups) {
- grantRuntimePermissions(packageName, permissionGroup, systemFixed,
- ignoreSystemPackage, userId);
- }
+ grantRuntimePermissionsForPackage(userId, pkg);
}
}
@@ -425,373 +379,594 @@ public final class DefaultPermissionGrantPolicy {
syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
// Installer
- grantSystemFixedPermissionsToSystemPackage(
- getKnownPackage(PackageManagerInternal.PACKAGE_INSTALLER, userId),
- userId, STORAGE_PERMISSIONS);
+ final String installerPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_INSTALLER, userId);
+ PackageParser.Package installerPackage = getSystemPackage(installerPackageName);
+ if (installerPackage != null
+ && doesPackageSupportRuntimePermissions(installerPackage)) {
+ grantRuntimePermissions(installerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
// Verifier
- final String verifier = getKnownPackage(PackageManagerInternal.PACKAGE_VERIFIER, userId);
- grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS);
- grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);
+ final String verifierPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_VERIFIER, userId);
+ PackageParser.Package verifierPackage = getSystemPackage(verifierPackageName);
+ if (verifierPackage != null
+ && doesPackageSupportRuntimePermissions(verifierPackage)) {
+ grantRuntimePermissions(verifierPackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(verifierPackage, PHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissions(verifierPackage, SMS_PERMISSIONS, false, userId);
+ }
// SetupWizard
- grantPermissionsToSystemPackage(
- getKnownPackage(PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId), userId,
- PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, LOCATION_PERMISSIONS, CAMERA_PERMISSIONS);
+ final String setupWizardPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId);
+ PackageParser.Package setupPackage = getSystemPackage(setupWizardPackageName);
+ if (setupPackage != null
+ && doesPackageSupportRuntimePermissions(setupPackage)) {
+ grantRuntimePermissions(setupPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, CAMERA_PERMISSIONS, userId);
+ }
// Camera
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId),
- userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS);
+ Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackage(
+ cameraIntent, userId);
+ if (cameraPackage != null
+ && doesPackageSupportRuntimePermissions(cameraPackage)) {
+ grantRuntimePermissions(cameraPackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(cameraPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(cameraPackage, STORAGE_PERMISSIONS, userId);
+ }
// Media provider
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId,
- STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS,
- PHONE_PERMISSIONS);
+ PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackage(
+ MediaStore.AUTHORITY, userId);
+ if (mediaStorePackage != null) {
+ grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(mediaStorePackage, MEDIA_AURAL_PERMISSIONS, true, userId);
+ grantRuntimePermissions(mediaStorePackage, MEDIA_VISUAL_PERMISSIONS, true, userId);
+ grantRuntimePermissions(mediaStorePackage, PHONE_PERMISSIONS, true, userId);
+ }
// Downloads provider
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultProviderAuthorityPackage("downloads", userId), userId,
- STORAGE_PERMISSIONS);
+ PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackage(
+ "downloads", userId);
+ if (downloadsPackage != null) {
+ grantRuntimePermissions(downloadsPackage, STORAGE_PERMISSIONS, true, userId);
+ }
// Downloads UI
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- DownloadManager.ACTION_VIEW_DOWNLOADS, userId),
- userId, STORAGE_PERMISSIONS);
+ Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
+ PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackage(
+ downloadsUiIntent, userId);
+ if (downloadsUiPackage != null
+ && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
+ grantRuntimePermissions(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId);
+ }
// Storage provider
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId),
- userId, STORAGE_PERMISSIONS);
+ PackageParser.Package storagePackage = getDefaultProviderAuthorityPackage(
+ "com.android.externalstorage.documents", userId);
+ if (storagePackage != null) {
+ grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
+ }
// CertInstaller
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId,
- STORAGE_PERMISSIONS);
+ Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
+ PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
+ certInstallerIntent, userId);
+ if (certInstallerPackage != null
+ && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
+ grantRuntimePermissions(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
// Dialer
if (dialerAppPackageNames == null) {
- String dialerPackage =
- getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId);
- grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
+ PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackage(
+ dialerIntent, userId);
+ if (dialerPackage != null) {
+ grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ }
} else {
for (String dialerAppPackageName : dialerAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId);
+ PackageParser.Package dialerPackage = getSystemPackage(dialerAppPackageName);
+ if (dialerPackage != null) {
+ grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ }
}
}
// Sim call manager
if (simCallManagerPackageNames != null) {
for (String simCallManagerPackageName : simCallManagerPackageNames) {
- grantDefaultPermissionsToDefaultSystemSimCallManager(
- simCallManagerPackageName, userId);
+ PackageParser.Package simCallManagerPackage =
+ getSystemPackage(simCallManagerPackageName);
+ if (simCallManagerPackage != null) {
+ grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage,
+ userId);
+ }
}
}
// Use Open Wifi
if (useOpenWifiAppPackageNames != null) {
for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
- useOpenWifiPackageName, userId);
+ PackageParser.Package useOpenWifiPackage =
+ getSystemPackage(useOpenWifiPackageName);
+ if (useOpenWifiPackage != null) {
+ grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(useOpenWifiPackage,
+ userId);
+ }
}
}
// SMS
if (smsAppPackageNames == null) {
- String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_MESSAGING, userId);
- grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ Intent smsIntent = new Intent(Intent.ACTION_MAIN);
+ smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
+ PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackage(
+ smsIntent, userId);
+ if (smsPackage != null) {
+ grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ }
} else {
- for (String smsPackage : smsAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ for (String smsPackageName : smsAppPackageNames) {
+ PackageParser.Package smsPackage = getSystemPackage(smsPackageName);
+ if (smsPackage != null) {
+ grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ }
}
}
// Cell Broadcast Receiver
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
- userId, SMS_PERMISSIONS);
+ Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
+ PackageParser.Package cbrPackage =
+ getDefaultSystemHandlerActivityPackage(cbrIntent, userId);
+ if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
+ grantRuntimePermissions(cbrPackage, SMS_PERMISSIONS, userId);
+ }
// Carrier Provisioning Service
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId),
- userId, SMS_PERMISSIONS);
+ Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION);
+ PackageParser.Package carrierProvPackage =
+ getDefaultSystemHandlerServicePackage(carrierProvIntent, userId);
+ if (carrierProvPackage != null
+ && doesPackageSupportRuntimePermissions(carrierProvPackage)) {
+ grantRuntimePermissions(carrierProvPackage, SMS_PERMISSIONS, false, userId);
+ }
// Calendar
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_CALENDAR, userId),
- userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS);
+ Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
+ calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
+ PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackage(
+ calendarIntent, userId);
+ if (calendarPackage != null
+ && doesPackageSupportRuntimePermissions(calendarPackage)) {
+ grantRuntimePermissions(calendarPackage, CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(calendarPackage, CONTACTS_PERMISSIONS, userId);
+ }
// Calendar provider
- String calendarProvider =
- getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId);
- grantPermissionsToSystemPackage(calendarProvider, userId,
- CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS);
+ PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackage(
+ CalendarContract.AUTHORITY, userId);
+ if (calendarProviderPackage != null) {
+ grantRuntimePermissions(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(calendarProviderPackage, CALENDAR_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
+ }
// Calendar provider sync adapters
- grantPermissionToEachSystemPackage(
- getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId),
- userId, CALENDAR_PERMISSIONS);
+ List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackages(
+ calendarSyncAdapterPackages, userId);
+ final int calendarSyncAdapterCount = calendarSyncAdapters.size();
+ for (int i = 0; i < calendarSyncAdapterCount; i++) {
+ PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
+ if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) {
+ grantRuntimePermissions(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId);
+ }
+ }
// Contacts
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_CONTACTS, userId),
- userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+ Intent contactsIntent = new Intent(Intent.ACTION_MAIN);
+ contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
+ PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackage(
+ contactsIntent, userId);
+ if (contactsPackage != null
+ && doesPackageSupportRuntimePermissions(contactsPackage)) {
+ grantRuntimePermissions(contactsPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(contactsPackage, PHONE_PERMISSIONS, userId);
+ }
// Contacts provider sync adapters
- grantPermissionToEachSystemPackage(
- getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId),
- userId, CONTACTS_PERMISSIONS);
+ List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackages(
+ contactsSyncAdapterPackages, userId);
+ final int contactsSyncAdapterCount = contactsSyncAdapters.size();
+ for (int i = 0; i < contactsSyncAdapterCount; i++) {
+ PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
+ if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) {
+ grantRuntimePermissions(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId);
+ }
+ }
// Contacts provider
- String contactsProviderPackage =
- getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId);
- grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId,
- CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
- grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS);
+ PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackage(
+ ContactsContract.AUTHORITY, userId);
+ if (contactsProviderPackage != null) {
+ grantRuntimePermissions(contactsProviderPackage, CONTACTS_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(contactsProviderPackage, PHONE_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
+ }
// Device provisioning
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
- userId, CONTACTS_PERMISSIONS);
+ Intent deviceProvisionIntent = new Intent(
+ DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
+ PackageParser.Package deviceProvisionPackage =
+ getDefaultSystemHandlerActivityPackage(deviceProvisionIntent, userId);
+ if (deviceProvisionPackage != null
+ && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
+ grantRuntimePermissions(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
+ }
// Maps
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId),
- userId, LOCATION_PERMISSIONS);
+ Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
+ mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
+ PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackage(
+ mapsIntent, userId);
+ if (mapsPackage != null
+ && doesPackageSupportRuntimePermissions(mapsPackage)) {
+ grantRuntimePermissions(mapsPackage, LOCATION_PERMISSIONS, userId);
+ }
// Gallery
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_GALLERY, userId),
- userId, STORAGE_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS);
+ Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
+ galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
+ PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackage(
+ galleryIntent, userId);
+ if (galleryPackage != null
+ && doesPackageSupportRuntimePermissions(galleryPackage)) {
+ grantRuntimePermissions(galleryPackage, STORAGE_PERMISSIONS, userId);
+ grantRuntimePermissions(galleryPackage, MEDIA_VISUAL_PERMISSIONS, userId);
+ }
// Email
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_EMAIL, userId),
- userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);
+ Intent emailIntent = new Intent(Intent.ACTION_MAIN);
+ emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
+ PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackage(
+ emailIntent, userId);
+ if (emailPackage != null
+ && doesPackageSupportRuntimePermissions(emailPackage)) {
+ grantRuntimePermissions(emailPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(emailPackage, CALENDAR_PERMISSIONS, userId);
+ }
// Browser
- String browserPackage = getKnownPackage(PackageManagerInternal.PACKAGE_BROWSER, userId);
+ PackageParser.Package browserPackage = null;
+ String defaultBrowserPackage = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_BROWSER, userId);
+ if (defaultBrowserPackage != null) {
+ browserPackage = getPackage(defaultBrowserPackage);
+ }
if (browserPackage == null) {
- browserPackage = getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_APP_BROWSER, userId);
- if (!isSystemPackage(browserPackage)) {
- browserPackage = null;
- }
+ Intent browserIntent = new Intent(Intent.ACTION_MAIN);
+ browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
+ browserPackage = getDefaultSystemHandlerActivityPackage(
+ browserIntent, userId);
+ }
+ if (browserPackage != null
+ && doesPackageSupportRuntimePermissions(browserPackage)) {
+ grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, userId);
}
- grantRuntimePermissionsToPackage(browserPackage, userId,
- false /* systemFixed */, false /* ignoreSystemPackage */,
- LOCATION_PERMISSIONS);
// Voice interaction
if (voiceInteractPackageNames != null) {
for (String voiceInteractPackageName : voiceInteractPackageNames) {
- grantPermissionsToSystemPackage(voiceInteractPackageName, userId,
- CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
- PHONE_PERMISSIONS, SMS_PERMISSIONS, LOCATION_PERMISSIONS);
+ PackageParser.Package voiceInteractPackage = getSystemPackage(
+ voiceInteractPackageName);
+ if (voiceInteractPackage != null
+ && doesPackageSupportRuntimePermissions(voiceInteractPackage)) {
+ grantRuntimePermissions(voiceInteractPackage,
+ CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ LOCATION_PERMISSIONS, userId);
+ }
}
}
if (ActivityManager.isLowRamDeviceStatic()) {
// Allow voice search on low-ram devices
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
- userId, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
+ Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH");
+ PackageParser.Package globalSearchPickerPackage =
+ getDefaultSystemHandlerActivityPackage(globalSearchIntent, userId);
+
+ if (globalSearchPickerPackage != null
+ && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) {
+ grantRuntimePermissions(globalSearchPickerPackage,
+ MICROPHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissions(globalSearchPickerPackage,
+ LOCATION_PERMISSIONS, false, userId);
+ }
}
// Voice recognition
- Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE)
- .addCategory(Intent.CATEGORY_DEFAULT);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId,
- MICROPHONE_PERMISSIONS);
+ Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
+ voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackage(
+ voiceRecoIntent, userId);
+ if (voiceRecoPackage != null
+ && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
+ grantRuntimePermissions(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
+ }
// Location
if (locationPackageNames != null) {
for (String packageName : locationPackageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
- CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
- PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
- SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(packageName, userId,
- LOCATION_PERMISSIONS);
+ PackageParser.Package locationPackage = getSystemPackage(packageName);
+ if (locationPackage != null
+ && doesPackageSupportRuntimePermissions(locationPackage)) {
+ grantRuntimePermissions(locationPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, LOCATION_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(locationPackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, SENSORS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, STORAGE_PERMISSIONS, userId);
+ }
}
}
// Music
- Intent musicIntent = new Intent(Intent.ACTION_VIEW)
- .addCategory(Intent.CATEGORY_DEFAULT)
- .setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId,
- STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
+ Intent musicIntent = new Intent(Intent.ACTION_VIEW);
+ musicIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")),
+ AUDIO_MIME_TYPE);
+ PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackage(
+ musicIntent, userId);
+ if (musicPackage != null
+ && doesPackageSupportRuntimePermissions(musicPackage)) {
+ grantRuntimePermissions(musicPackage, STORAGE_PERMISSIONS, userId);
+ grantRuntimePermissions(musicPackage, MEDIA_AURAL_PERMISSIONS, userId);
+ }
// Home
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .addCategory(Intent.CATEGORY_LAUNCHER_APP);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId,
- LOCATION_PERMISSIONS);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP);
+ PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackage(
+ homeIntent, userId);
+ if (homePackage != null
+ && doesPackageSupportRuntimePermissions(homePackage)) {
+ grantRuntimePermissions(homePackage, LOCATION_PERMISSIONS, false, userId);
+ }
// Watches
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
// Home application on watches
-
- String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(
- Intent.CATEGORY_HOME_MAIN, userId);
- grantPermissionsToSystemPackage(wearPackage, userId,
- CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS);
+ Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN);
+ wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
+
+ PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackage(
+ wearHomeIntent, userId);
+
+ if (wearHomePackage != null
+ && doesPackageSupportRuntimePermissions(wearHomePackage)) {
+ grantRuntimePermissions(wearHomePackage, CONTACTS_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissions(wearHomePackage, PHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(wearHomePackage, MICROPHONE_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissions(wearHomePackage, LOCATION_PERMISSIONS, false,
+ userId);
+ }
// Fitness tracking on watches
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId,
- SENSORS_PERMISSIONS, LOCATION_PERMISSIONS);
+ Intent trackIntent = new Intent(ACTION_TRACK);
+ PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackage(
+ trackIntent, userId);
+ if (trackPackage != null
+ && doesPackageSupportRuntimePermissions(trackPackage)) {
+ grantRuntimePermissions(trackPackage, SENSORS_PERMISSIONS, false, userId);
+ grantRuntimePermissions(trackPackage, LOCATION_PERMISSIONS, false, userId);
+ }
}
// Print Spooler
- grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId,
- LOCATION_PERMISSIONS);
+ PackageParser.Package printSpoolerPackage = getSystemPackage(
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
+ if (printSpoolerPackage != null
+ && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
+ grantRuntimePermissions(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
+ }
// EmergencyInfo
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
- userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+ Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+ PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackage(
+ emergencyInfoIntent, userId);
+ if (emergencyInfoPckg != null
+ && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
+ grantRuntimePermissions(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
+ grantRuntimePermissions(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
+ }
// NFC Tag viewer
- Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
- .setType("vnd.android.cursor.item/ndef_msg");
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId,
- CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+ Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+ nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+ PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackage(
+ nfcTagIntent, userId);
+ if (nfcTagPkg != null
+ && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+ grantRuntimePermissions(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+ grantRuntimePermissions(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+ }
// Storage Manager
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- StorageManager.ACTION_MANAGE_STORAGE, userId),
- userId, STORAGE_PERMISSIONS);
+ Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+ PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackage(
+ storageManagerIntent, userId);
+ if (storageManagerPckg != null
+ && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
+ grantRuntimePermissions(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
+ }
// Companion devices
- grantSystemFixedPermissionsToSystemPackage(
- CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId,
- LOCATION_PERMISSIONS);
+ PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackage(
+ CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
+ if (companionDeviceDiscoveryPackage != null
+ && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
+ grantRuntimePermissions(companionDeviceDiscoveryPackage,
+ LOCATION_PERMISSIONS, true, userId);
+ }
// Ringtone Picker
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
- RingtoneManager.ACTION_RINGTONE_PICKER, userId),
- userId, STORAGE_PERMISSIONS);
+ Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+ PackageParser.Package ringtonePickerPackage =
+ getDefaultSystemHandlerActivityPackage(ringtonePickerIntent, userId);
+ if (ringtonePickerPackage != null
+ && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) {
+ grantRuntimePermissions(ringtonePickerPackage,
+ STORAGE_PERMISSIONS, true, userId);
+ }
// TextClassifier Service
String textClassifierPackageName =
mContext.getPackageManager().getSystemTextClassifierPackageName();
if (!TextUtils.isEmpty(textClassifierPackageName)) {
- grantPermissionsToSystemPackage(textClassifierPackageName, userId,
- PHONE_PERMISSIONS, SMS_PERMISSIONS, CALENDAR_PERMISSIONS,
- LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
+ PackageParser.Package textClassifierPackage =
+ getSystemPackage(textClassifierPackageName);
+ if (textClassifierPackage != null
+ && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
+ grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId);
+ grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId);
+ grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId);
+ grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId);
+ }
}
// There is no real "marker" interface to identify the shared storage backup, it is
// hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
- grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
- STORAGE_PERMISSIONS);
+ PackageParser.Package sharedStorageBackupPackage = getSystemPackage(
+ "com.android.sharedstoragebackup");
+ if (sharedStorageBackupPackage != null) {
+ grantRuntimePermissions(sharedStorageBackupPackage, STORAGE_PERMISSIONS, true, userId);
+ }
if (mPermissionGrantedCallback != null) {
mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId);
}
}
- private String getDefaultSystemHandlerActivityPackageForCategory(String category, int userId) {
- return getDefaultSystemHandlerActivityPackage(
- new Intent(Intent.ACTION_MAIN).addCategory(category), userId);
- }
-
- @SafeVarargs
- private final void grantPermissionToEachSystemPackage(
- ArrayList<String> packages, int userId, Set<String>... permissions) {
- if (packages == null) return;
- final int count = packages.size();
- for (int i = 0; i < count; i++) {
- grantPermissionsToSystemPackage(packages.get(i), userId, permissions);
- }
- }
-
- private String getKnownPackage(int knownPkgId, int userId) {
- return mServiceInternal.getKnownPackageName(knownPkgId, userId);
- }
-
private void grantDefaultPermissionsToDefaultSystemDialerApp(
- String dialerPackage, int userId) {
- if (dialerPackage == null) {
- return;
- }
- boolean isPhonePermFixed =
- mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
- if (isPhonePermFixed) {
- grantSystemFixedPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
- } else {
- grantPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+ PackageParser.Package dialerPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(dialerPackage)) {
+ boolean isPhonePermFixed =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
+ grantRuntimePermissions(
+ dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
+ grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, userId);
}
- grantPermissionsToSystemPackage(dialerPackage, userId,
- CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
}
- private void grantDefaultPermissionsToDefaultSystemSmsApp(String smsPackage, int userId) {
- grantPermissionsToSystemPackage(smsPackage, userId,
- PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
- STORAGE_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
+ private void grantDefaultPermissionsToDefaultSystemSmsApp(
+ PackageParser.Package smsPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(smsPackage)) {
+ grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, userId);
+ }
}
private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
- String useOpenWifiPackage, int userId) {
- grantPermissionsToSystemPackage(
- useOpenWifiPackage, userId, COARSE_LOCATION_PERMISSIONS);
+ PackageParser.Package useOpenWifiPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
+ grantRuntimePermissions(useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, userId);
+ }
}
public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
- grantIgnoringSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, STORAGE_PERMISSIONS,
- MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package smsPackage = getPackage(packageName);
+ if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) {
+ grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
+ }
}
public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
- mServiceInternal.onDefaultDialerAppChanged(packageName, userId);
Log.i(TAG, "Granting permissions to default dialer app for user:" + userId);
- grantIgnoringSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
- MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package dialerPackage = getPackage(packageName);
+ if (dialerPackage != null
+ && doesPackageSupportRuntimePermissions(dialerPackage)) {
+ grantRuntimePermissions(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
+ }
}
public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
- grantIgnoringSystemPackage(packageName, userId, COARSE_LOCATION_PERMISSIONS);
- }
-
- public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
if (packageName == null) {
return;
}
+ PackageParser.Package useOpenWifiPackage = getPackage(packageName);
+ if (useOpenWifiPackage != null
+ && doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
+ grantRuntimePermissions(
+ useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, false, true, userId);
+ }
+ }
+
+ private void grantDefaultPermissionsToDefaultSimCallManager(
+ PackageParser.Package simCallManagerPackage, int userId) {
Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
- grantRuntimePermissionsToPackage(packageName, userId, false, false,
- PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
+ if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) {
+ grantRuntimePermissions(simCallManagerPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId);
+ }
}
- private void grantDefaultPermissionsToDefaultSystemSimCallManager(
- String packageName, int userId) {
- if (isSystemPackage(packageName)) {
- grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
+ public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package simCallManagerPackage = getPackage(packageName);
+ if (simCallManagerPackage != null) {
+ grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, userId);
}
}
@@ -801,8 +976,13 @@ public final class DefaultPermissionGrantPolicy {
return;
}
for (String packageName : packageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, LOCATION_PERMISSIONS, SMS_PERMISSIONS);
+ PackageParser.Package carrierPackage = getSystemPackage(packageName);
+ if (carrierPackage != null
+ && doesPackageSupportRuntimePermissions(carrierPackage)) {
+ grantRuntimePermissions(carrierPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(carrierPackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(carrierPackage, SMS_PERMISSIONS, userId);
+ }
}
}
@@ -812,9 +992,15 @@ public final class DefaultPermissionGrantPolicy {
return;
}
for (String packageName : packageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS,
- CAMERA_PERMISSIONS, CONTACTS_PERMISSIONS);
+ PackageParser.Package imsServicePackage = getSystemPackage(packageName);
+ if (imsServicePackage != null
+ && doesPackageSupportRuntimePermissions(imsServicePackage)) {
+ grantRuntimePermissions(imsServicePackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, CONTACTS_PERMISSIONS, userId);
+ }
}
}
@@ -825,12 +1011,15 @@ public final class DefaultPermissionGrantPolicy {
return;
}
for (String packageName : packageNames) {
- // Grant these permissions as system-fixed, so that nobody can accidentally
- // break cellular data.
- grantSystemFixedPermissionsToSystemPackage(packageName, userId,
- PHONE_PERMISSIONS, LOCATION_PERMISSIONS);
+ PackageParser.Package dataServicePackage = getSystemPackage(packageName);
+ if (dataServicePackage != null
+ && doesPackageSupportRuntimePermissions(dataServicePackage)) {
+ // Grant these permissions as system-fixed, so that nobody can accidentally
+ // break cellular data.
+ grantRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
+ }
}
-
}
public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
@@ -840,17 +1029,25 @@ public final class DefaultPermissionGrantPolicy {
return;
}
for (String packageName : packageNames) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
- if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
- revokeRuntimePermissions(packageName, PHONE_PERMISSIONS, true, userId);
- revokeRuntimePermissions(packageName, LOCATION_PERMISSIONS, true, userId);
+ PackageParser.Package dataServicePackage = getSystemPackage(packageName);
+ if (dataServicePackage != null
+ && doesPackageSupportRuntimePermissions(dataServicePackage)) {
+ revokeRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
+ revokeRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
}
}
}
public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to active LUI app for user:" + userId);
- grantSystemFixedPermissionsToSystemPackage(packageName, userId, CAMERA_PERMISSIONS);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package luiAppPackage = getSystemPackage(packageName);
+ if (luiAppPackage != null
+ && doesPackageSupportRuntimePermissions(luiAppPackage)) {
+ grantRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
+ }
}
public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
@@ -859,116 +1056,123 @@ public final class DefaultPermissionGrantPolicy {
return;
}
for (String packageName : packageNames) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
- if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
- revokeRuntimePermissions(packageName, CAMERA_PERMISSIONS, true, userId);
+ PackageParser.Package luiAppPackage = getSystemPackage(packageName);
+ if (luiAppPackage != null
+ && doesPackageSupportRuntimePermissions(luiAppPackage)) {
+ revokeRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
}
}
}
public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default browser for user:" + userId);
- grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
- }
-
- private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) {
- return getDefaultSystemHandlerActivityPackage(new Intent(intentAction), userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package browserPackage = getSystemPackage(packageName);
+ if (browserPackage != null
+ && doesPackageSupportRuntimePermissions(browserPackage)) {
+ grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, false, false, userId);
+ }
}
- private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
+ private PackageParser.Package getDefaultSystemHandlerActivityPackage(
+ Intent intent, int userId) {
ResolveInfo handler = mServiceInternal.resolveIntent(intent,
- intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS,
- userId, false, Binder.getCallingUid());
+ intent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, userId, false,
+ Binder.getCallingUid());
if (handler == null || handler.activityInfo == null) {
return null;
}
if (mServiceInternal.isResolveActivityComponent(handler.activityInfo)) {
return null;
}
- String packageName = handler.activityInfo.packageName;
- return isSystemPackage(packageName) ? packageName : null;
- }
-
- private String getDefaultSystemHandlerServicePackage(String intentAction, int userId) {
- return getDefaultSystemHandlerServicePackage(new Intent(intentAction), userId);
+ return getSystemPackage(handler.activityInfo.packageName);
}
- private String getDefaultSystemHandlerServicePackage(
+ private PackageParser.Package getDefaultSystemHandlerServicePackage(
Intent intent, int userId) {
List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
- intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId);
+ intent, DEFAULT_FLAGS, Binder.getCallingUid(), userId);
if (handlers == null) {
return null;
}
final int handlerCount = handlers.size();
for (int i = 0; i < handlerCount; i++) {
ResolveInfo handler = handlers.get(i);
- String handlerPackage = handler.serviceInfo.packageName;
- if (isSystemPackage(handlerPackage)) {
+ PackageParser.Package handlerPackage = getSystemPackage(
+ handler.serviceInfo.packageName);
+ if (handlerPackage != null) {
return handlerPackage;
}
}
return null;
}
- private ArrayList<String> getHeadlessSyncAdapterPackages(
+ private List<PackageParser.Package> getHeadlessSyncAdapterPackages(
String[] syncAdapterPackageNames, int userId) {
- ArrayList<String> syncAdapterPackages = new ArrayList<>();
+ List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
- Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
for (String syncAdapterPackageName : syncAdapterPackageNames) {
homeIntent.setPackage(syncAdapterPackageName);
ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
- homeIntent.resolveType(mContext.getContentResolver()),
- DEFAULT_INTENT_QUERY_FLAGS,
+ homeIntent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS,
userId, false, Binder.getCallingUid());
if (homeActivity != null) {
continue;
}
- if (isSystemPackage(syncAdapterPackageName)) {
- syncAdapterPackages.add(syncAdapterPackageName);
+ PackageParser.Package syncAdapterPackage = getSystemPackage(syncAdapterPackageName);
+ if (syncAdapterPackage != null) {
+ syncAdapterPackages.add(syncAdapterPackage);
}
}
return syncAdapterPackages;
}
- private String getDefaultProviderAuthorityPackage(String authority, int userId) {
- ProviderInfo provider = mServiceInternal.resolveContentProvider(
- authority, DEFAULT_INTENT_QUERY_FLAGS, userId);
+ private PackageParser.Package getDefaultProviderAuthorityPackage(
+ String authority, int userId) {
+ ProviderInfo provider =
+ mServiceInternal.resolveContentProvider(authority, DEFAULT_FLAGS, userId);
if (provider != null) {
- return provider.packageName;
+ return getSystemPackage(provider.packageName);
}
return null;
}
- private boolean isSystemPackage(String packageName) {
- return isSystemPackage(getSystemPackageInfo(packageName));
+ private PackageParser.Package getPackage(String packageName) {
+ return mServiceInternal.getPackage(packageName);
}
- private boolean isSystemPackage(PackageInfo pkg) {
- if (pkg == null) {
- return false;
+ private PackageParser.Package getSystemPackage(String packageName) {
+ PackageParser.Package pkg = getPackage(packageName);
+ if (pkg != null && pkg.isSystem()) {
+ return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
}
- return pkg.applicationInfo.isSystemApp()
- && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg);
+ return null;
}
- private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions,
+ private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+ int userId) {
+ grantRuntimePermissions(pkg, permissions, false, false, userId);
+ }
+
+ private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
boolean systemFixed, int userId) {
grantRuntimePermissions(pkg, permissions, systemFixed, false, userId);
}
- private void revokeRuntimePermissions(String packageName, Set<String> permissions,
+ private void revokeRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
boolean systemFixed, int userId) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
- if (ArrayUtils.isEmpty(pkg.requestedPermissions)) {
+ if (pkg.requestedPermissions.isEmpty()) {
return;
}
- Set<String> revokablePermissions = new ArraySet<>(Arrays.asList(pkg.requestedPermissions));
+ Set<String> revokablePermissions = new ArraySet<>(pkg.requestedPermissions);
for (String permission : permissions) {
// We can't revoke what wasn't requested.
@@ -977,7 +1181,7 @@ public final class DefaultPermissionGrantPolicy {
}
final int flags = mServiceInternal.getPermissionFlagsTEMP(
- permission, packageName, userId);
+ permission, pkg.packageName, userId);
// We didn't get this through the default grant policy. Move along.
if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -993,35 +1197,29 @@ public final class DefaultPermissionGrantPolicy {
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
continue;
}
- mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false);
+ mServiceInternal.revokeRuntimePermission(pkg.packageName, permission, userId, false);
if (DEBUG) {
Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
- + permission + " to " + packageName);
+ + permission + " to " + pkg.packageName);
}
// Remove the GRANTED_BY_DEFAULT flag without touching the others.
// Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
// sticky once set.
- mServiceInternal.updatePermissionFlagsTEMP(permission, packageName,
+ mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId);
}
}
- private void grantRuntimePermissions(PackageInfo pkg,
+ private void grantRuntimePermissions(PackageParser.Package pkg,
Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
int userId) {
- if (pkg == null) {
- return;
- }
-
- String[] requestedPermissions = pkg.requestedPermissions;
- if (ArrayUtils.isEmpty(requestedPermissions)) {
+ if (pkg.requestedPermissions.isEmpty()) {
return;
}
final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
- ApplicationInfo applicationInfo = pkg.applicationInfo;
// Automatically attempt to grant split permissions to older APKs
final int numSplitPerms = PackageParser.SPLIT_PERMISSIONS.length;
@@ -1029,13 +1227,13 @@ public final class DefaultPermissionGrantPolicy {
final PackageParser.SplitPermissionInfo splitPerm =
PackageParser.SPLIT_PERMISSIONS[splitPermNum];
- if (applicationInfo != null
- && applicationInfo.targetSdkVersion < splitPerm.targetSdk
+ if (pkg.applicationInfo.targetSdkVersion < splitPerm.targetSdk
&& permissionsWithoutSplits.contains(splitPerm.rootPerm)) {
Collections.addAll(permissions, splitPerm.newPerms);
}
}
+ List<String> requestedPermissions = pkg.requestedPermissions;
Set<String> grantablePermissions = null;
// In some cases, like for the Phone or SMS app, we grant permissions regardless
@@ -1044,25 +1242,23 @@ public final class DefaultPermissionGrantPolicy {
// choice to grant this app the permissions needed to function. For all other
// apps, (default grants on first boot and user creation) we don't grant default
// permissions if the version on the system image does not declare them.
- if (!ignoreSystemPackage
- && applicationInfo != null
- && applicationInfo.isUpdatedSystemApp()) {
- final PackageInfo disabledPkg = getSystemPackageInfo(
- mServiceInternal.getDisabledSystemPackageName(pkg.packageName));
+ if (!ignoreSystemPackage && pkg.isUpdatedSystemApp()) {
+ final PackageParser.Package disabledPkg =
+ mServiceInternal.getDisabledPackage(pkg.packageName);
if (disabledPkg != null) {
- if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
+ if (disabledPkg.requestedPermissions.isEmpty()) {
return;
}
if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) {
- grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions));
+ grantablePermissions = new ArraySet<>(requestedPermissions);
requestedPermissions = disabledPkg.requestedPermissions;
}
}
}
- final int grantablePermissionCount = requestedPermissions.length;
+ final int grantablePermissionCount = requestedPermissions.size();
for (int i = 0; i < grantablePermissionCount; i++) {
- String permission = requestedPermissions[i];
+ String permission = requestedPermissions.get(i);
// If there is a disabled system app it may request a permission the updated
// version ot the data partition doesn't, In this case skip the permission.
@@ -1092,7 +1288,7 @@ public final class DefaultPermissionGrantPolicy {
pkg.packageName, permission, userId, false);
if (DEBUG) {
Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
- + permission + " to default handler " + pkg);
+ + permission + " to default handler " + pkg.packageName);
}
int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -1111,7 +1307,7 @@ public final class DefaultPermissionGrantPolicy {
&& !systemFixed) {
if (DEBUG) {
Log.i(TAG, "Granted not fixed " + permission + " to default handler "
- + pkg);
+ + pkg.packageName);
}
mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
@@ -1120,42 +1316,28 @@ public final class DefaultPermissionGrantPolicy {
}
}
- private PackageInfo getSystemPackageInfo(String pkg) {
- //TODO not MATCH_SYSTEM_ONLY?
- return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY);
- }
-
- private PackageInfo getPackageInfo(String pkg) {
- return getPackageInfo(pkg, 0 /* extraFlags */);
- }
-
- private PackageInfo getPackageInfo(String pkg,
- @PackageManager.PackageInfoFlags int extraFlags) {
- return mServiceInternal.getPackageInfo(pkg,
- DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags,
- //TODO is this the right filterCallingUid?
- UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM);
- }
-
- private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
+ private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
return true;
}
- if (!pkg.applicationInfo.isPrivilegedApp()) {
+ if (!pkg.isPrivileged()) {
return false;
}
- final PackageInfo disabledPkg = getSystemPackageInfo(
- mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
+ final PackageParser.Package disabledPkg =
+ mServiceInternal.getDisabledPackage(pkg.packageName);
if (disabledPkg != null) {
- ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
- if (disabledPackageAppInfo != null
- && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ if ((disabledPkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
return false;
}
} else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
return false;
}
- return mServiceInternal.isPlatformSigned(pkg.packageName);
+ final String systemPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
+ final PackageParser.Package systemPackage = getPackage(systemPackageName);
+ return pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
+ || systemPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.PERMISSION);
}
private void grantDefaultPermissionExceptions(int userId) {
@@ -1175,7 +1357,7 @@ public final class DefaultPermissionGrantPolicy {
final int exceptionCount = mGrantExceptions.size();
for (int i = 0; i < exceptionCount; i++) {
String packageName = mGrantExceptions.keyAt(i);
- PackageInfo pkg = getSystemPackageInfo(packageName);
+ PackageParser.Package pkg = getSystemPackage(packageName);
List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
final int permissionGrantCount = permissionGrants.size();
for (int j = 0; j < permissionGrantCount; j++) {
@@ -1186,7 +1368,8 @@ public final class DefaultPermissionGrantPolicy {
permissions.clear();
}
permissions.add(permissionGrant.name);
- grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
+ grantRuntimePermissions(pkg, permissions,
+ permissionGrant.fixed, userId);
}
}
}
@@ -1291,14 +1474,15 @@ public final class DefaultPermissionGrantPolicy {
outGrantExceptions.get(packageName);
if (packageExceptions == null) {
// The package must be on the system image
- if (!isSystemPackage(packageName)) {
+ PackageParser.Package pkg = getSystemPackage(packageName);
+ if (pkg == null) {
Log.w(TAG, "Unknown package:" + packageName);
XmlUtils.skipCurrentTag(parser);
continue;
}
// The package must support runtime permissions
- if (!doesPackageSupportRuntimePermissions(getSystemPackageInfo(packageName))) {
+ if (!doesPackageSupportRuntimePermissions(pkg)) {
Log.w(TAG, "Skipping non supporting runtime permissions package:"
+ packageName);
XmlUtils.skipCurrentTag(parser);
@@ -1343,9 +1527,8 @@ public final class DefaultPermissionGrantPolicy {
}
}
- private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) {
- return pkg.applicationInfo != null
- && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
+ return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
}
private static final class DefaultPermissionGrant {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4b6760c6405a..c4f90a125c71 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1189,7 +1189,7 @@ public class PermissionManagerService {
// is granted only if it had been defined by the original application.
if (pkg.isUpdatedSystemApp()) {
final PackageParser.Package disabledPkg =
- mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
+ mPackageManagerInt.getDisabledPackage(pkg.packageName);
final PackageSetting disabledPs =
(disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
if (disabledPs != null
@@ -1221,7 +1221,7 @@ public class PermissionManagerService {
// packages can also get the permission.
if (pkg.parentPackage != null) {
final PackageParser.Package disabledParentPkg = mPackageManagerInt
- .getDisabledSystemPackage(pkg.parentPackage.packageName);
+ .getDisabledPackage(pkg.parentPackage.packageName);
final PackageSetting disabledParentPs = (disabledParentPkg != null)
? (PackageSetting) disabledParentPkg.mExtras : null;
if (disabledParentPkg != null
@@ -1372,7 +1372,7 @@ public class PermissionManagerService {
return;
}
final PackageParser.Package disabledPkg =
- mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
+ mPackageManagerInt.getDisabledPackage(pkg.parentPackage.packageName);
if (disabledPkg == null || disabledPkg.mExtras == null) {
return;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 350d6b66c1fb..3b19beb52e2e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3543,8 +3543,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
} else if (mHasFeatureLeanback && interceptBugreportGestureTv(keyCode, down)) {
return -1;
- } else if (mHasFeatureLeanback && interceptAccessibilityGestureTv(keyCode, down)) {
- return -1;
} else if (keyCode == KeyEvent.KEYCODE_ALL_APPS) {
if (!down) {
mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
@@ -6037,6 +6035,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ // Intercept the Accessibility keychord for TV (DPAD_DOWN + Back) before the keyevent is
+ // processed through interceptKeyEventBeforeDispatch since Talkback may consume this event
+ // before it has a chance to reach that method.
+ if (mHasFeatureLeanback) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_BACK: {
+ boolean handled = interceptAccessibilityGestureTv(keyCode, down);
+ if (handled) {
+ result &= ~ACTION_PASS_TO_USER;
+ }
+ break;
+ }
+ }
+ }
+
if (useHapticFeedback) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
"Virtual Key - Press");
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 20918995a8ee..444ac2c041d5 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -32,6 +32,7 @@ import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.fingerprint.FingerprintManager;
import android.net.NetworkStats;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
@@ -976,10 +977,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ looperStats.reset();
long elapsedNanos = SystemClock.elapsedRealtimeNanos();
for (LooperStats.ExportedEntry entry : entries) {
- StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 9 /* fields */);
- e.writeLong(0); // uid collection not implemented yet
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 10 /* fields */);
+ e.writeInt(1000); // uid collection not implemented yet
e.writeString(entry.handlerClassName);
e.writeString(entry.threadName);
e.writeString(entry.messageName);
@@ -988,6 +990,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeLong(entry.recordedMessageCount);
e.writeLong(entry.totalLatencyMicros);
e.writeLong(entry.cpuUsageMicros);
+ e.writeBoolean(entry.isInteractive);
pulledData.add(e);
}
}
@@ -1169,6 +1172,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ private void pullNumFingerprints(int tagId, List<StatsLogEventWrapper> pulledData) {
+ FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ if (fingerprintManager == null) {
+ return;
+ }
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ if (userManager == null) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ for (UserInfo user : userManager.getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int numFingerprints = fingerprintManager.getEnrolledFingerprints(userId).size();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2 /* fields */);
+ e.writeInt(userId);
+ e.writeInt(numFingerprints);
+ pulledData.add(e);
+ }
+ Binder.restoreCallingIdentity(token);
+ }
+
/**
* Pulls various data.
*/
@@ -1275,6 +1300,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullCategorySize(tagId, ret);
break;
}
+ case StatsLog.NUM_FINGERPRINTS: {
+ pullNumFingerprints(tagId, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 7a3f030f9dd7..6c5452a3cb2e 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -38,13 +39,12 @@ import android.telephony.CarrierConfigManager;
import android.util.IntArray;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.SmsApplication;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.PermissionManagerInternal;
/**
* Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -72,8 +72,8 @@ public class TelecomLoaderService extends SystemService {
synchronized (mLock) {
if (mDefaultSmsAppRequests != null || mDefaultDialerAppRequests != null
|| mDefaultSimCallManagerRequests != null) {
- final DefaultPermissionGrantPolicy permissionPolicy =
- getDefaultPermissionGrantPolicy();
+ final PackageManagerInternal packageManagerInternal = LocalServices
+ .getService(PackageManagerInternal.class);
if (mDefaultSmsAppRequests != null) {
ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
@@ -83,7 +83,7 @@ public class TelecomLoaderService extends SystemService {
for (int i = requestCount - 1; i >= 0; i--) {
final int userid = mDefaultSmsAppRequests.get(i);
mDefaultSmsAppRequests.remove(i);
- permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
+ packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
smsComponent.getPackageName(), userid);
}
}
@@ -97,7 +97,7 @@ public class TelecomLoaderService extends SystemService {
for (int i = requestCount - 1; i >= 0; i--) {
final int userId = mDefaultDialerAppRequests.get(i);
mDefaultDialerAppRequests.remove(i);
- permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
+ packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
packageName, userId);
}
}
@@ -113,7 +113,7 @@ public class TelecomLoaderService extends SystemService {
for (int i = requestCount - 1; i >= 0; i--) {
final int userId = mDefaultSimCallManagerRequests.get(i);
mDefaultSimCallManagerRequests.remove(i);
- permissionPolicy
+ packageManagerInternal
.grantDefaultPermissionsToDefaultSimCallManager(
packageName, userId);
}
@@ -132,11 +132,6 @@ public class TelecomLoaderService extends SystemService {
}
}
- private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
- return LocalServices.getService(PermissionManagerInternal.class)
- .getDefaultPermissionGrantPolicy();
- }
-
private static final ComponentName SERVICE_COMPONENT = new ComponentName(
"com.android.server.telecom",
"com.android.server.telecom.components.TelecomService");
@@ -201,68 +196,82 @@ public class TelecomLoaderService extends SystemService {
private void registerDefaultAppProviders() {
- final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
-
- // Set a callback for the permission grant policy to query the default sms app.
- permissionPolicy.setSmsAppPackagesProvider(userId -> {
- synchronized (mLock) {
- if (mServiceConnection == null) {
- if (mDefaultSmsAppRequests == null) {
- mDefaultSmsAppRequests = new IntArray();
+ final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+
+ // Set a callback for the package manager to query the default sms app.
+ packageManagerInternal.setSmsAppPackagesProvider(
+ new PackageManagerInternal.PackagesProvider() {
+ @Override
+ public String[] getPackages(int userId) {
+ synchronized (mLock) {
+ if (mServiceConnection == null) {
+ if (mDefaultSmsAppRequests == null) {
+ mDefaultSmsAppRequests = new IntArray();
+ }
+ mDefaultSmsAppRequests.add(userId);
+ return null;
}
- mDefaultSmsAppRequests.add(userId);
- return null;
}
+ ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
+ mContext, true);
+ if (smsComponent != null) {
+ return new String[]{smsComponent.getPackageName()};
+ }
+ return null;
}
- ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
- mContext, true);
- if (smsComponent != null) {
- return new String[]{smsComponent.getPackageName()};
- }
- return null;
});
- // Set a callback for the permission grant policy to query the default dialer app.
- permissionPolicy.setDialerAppPackagesProvider(userId -> {
- synchronized (mLock) {
- if (mServiceConnection == null) {
- if (mDefaultDialerAppRequests == null) {
- mDefaultDialerAppRequests = new IntArray();
+ // Set a callback for the package manager to query the default dialer app.
+ packageManagerInternal.setDialerAppPackagesProvider(
+ new PackageManagerInternal.PackagesProvider() {
+ @Override
+ public String[] getPackages(int userId) {
+ synchronized (mLock) {
+ if (mServiceConnection == null) {
+ if (mDefaultDialerAppRequests == null) {
+ mDefaultDialerAppRequests = new IntArray();
+ }
+ mDefaultDialerAppRequests.add(userId);
+ return null;
}
- mDefaultDialerAppRequests.add(userId);
- return null;
}
+ String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
+ if (packageName != null) {
+ return new String[]{packageName};
+ }
+ return null;
}
- String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
- if (packageName != null) {
- return new String[]{packageName};
- }
- return null;
});
- // Set a callback for the permission grant policy to query the default sim call manager.
- permissionPolicy.setSimCallManagerPackagesProvider(userId -> {
- synchronized (mLock) {
- if (mServiceConnection == null) {
- if (mDefaultSimCallManagerRequests == null) {
- mDefaultSimCallManagerRequests = new IntArray();
+ // Set a callback for the package manager to query the default sim call manager.
+ packageManagerInternal.setSimCallManagerPackagesProvider(
+ new PackageManagerInternal.PackagesProvider() {
+ @Override
+ public String[] getPackages(int userId) {
+ synchronized (mLock) {
+ if (mServiceConnection == null) {
+ if (mDefaultSimCallManagerRequests == null) {
+ mDefaultSimCallManagerRequests = new IntArray();
+ }
+ mDefaultSimCallManagerRequests.add(userId);
+ return null;
}
- mDefaultSimCallManagerRequests.add(userId);
- return null;
}
- }
- TelecomManager telecomManager =
+ TelecomManager telecomManager =
(TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
- PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
- if (phoneAccount != null) {
- return new String[]{phoneAccount.getComponentName().getPackageName()};
+ PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
+ if (phoneAccount != null) {
+ return new String[]{phoneAccount.getComponentName().getPackageName()};
+ }
+ return null;
}
- return null;
});
}
private void registerDefaultAppNotifier() {
- final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
+ final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
// Notify the package manager on default app changes
final Uri defaultSmsAppUri = Settings.Secure.getUriFor(
@@ -278,17 +287,17 @@ public class TelecomLoaderService extends SystemService {
ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
mContext, true);
if (smsComponent != null) {
- permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
+ packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
smsComponent.getPackageName(), userId);
}
} else if (defaultDialerAppUri.equals(uri)) {
String packageName = DefaultDialerManager.getDefaultDialerApplication(
mContext);
if (packageName != null) {
- permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
+ packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
packageName, userId);
}
- updateSimCallManagerPermissions(permissionPolicy, userId);
+ updateSimCallManagerPermissions(packageManagerInternal, userId);
}
}
};
@@ -301,12 +310,14 @@ public class TelecomLoaderService extends SystemService {
private void registerCarrierConfigChangedReceiver() {
+ final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
for (int userId : UserManagerService.getInstance().getUserIds()) {
- updateSimCallManagerPermissions(getDefaultPermissionGrantPolicy(), userId);
+ updateSimCallManagerPermissions(packageManagerInternal, userId);
}
}
}
@@ -316,15 +327,15 @@ public class TelecomLoaderService extends SystemService {
new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null, null);
}
- private void updateSimCallManagerPermissions(
- DefaultPermissionGrantPolicy permissionGrantPolicy, int userId) {
+ private void updateSimCallManagerPermissions(PackageManagerInternal packageManagerInternal,
+ int userId) {
TelecomManager telecomManager =
(TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
if (phoneAccount != null) {
Slog.i(TAG, "updating sim call manager permissions for userId:" + userId);
String packageName = phoneAccount.getComponentName().getPackageName();
- permissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+ packageManagerInternal.grantDefaultPermissionsToDefaultSimCallManager(
packageName, userId);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ac6582634bf8..6c7304dc052f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -409,6 +409,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private InputMonitor mInputMonitor;
+ /** Caches the value whether told display manager that we have content. */
+ private boolean mLastHasContent;
+
/**
* The input method window for this display.
*/
@@ -3092,8 +3095,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
prepareSurfaces();
+ mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
- mTmpApplySurfaceChangesTransactionState.displayHasContent,
+ mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
true /* inTraversal, must call performTraversalInTrans... below */);
@@ -4267,4 +4271,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
InputMonitor getInputMonitor() {
return mInputMonitor;
}
+
+ /**
+ * @return Cached value whether we told display manager that we have content.
+ */
+ boolean getLastHasContent() {
+ return mLastHasContent;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 685c444d92b5..bd82553b804b 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -21,6 +21,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -732,10 +733,13 @@ public class DisplayRotation {
boolean shouldUpdateOrientationListener = false;
// Configure rotation suggestions.
- final int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
- Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
- UserHandle.USER_CURRENT);
+ final int showRotationSuggestions =
+ ActivityManager.isLowRamDeviceStatic()
+ ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
+ : Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
+ Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
+ UserHandle.USER_CURRENT);
if (mShowRotationSuggestions != showRotationSuggestions) {
mShowRotationSuggestions = showRotationSuggestions;
shouldUpdateOrientationListener = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ed09ae2daf3..ee128c7abe7f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7411,32 +7411,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public boolean inputMethodClientHasFocus(IInputMethodClient client) {
- boolean hasFocus;
- synchronized (mWindowMap) {
- // Check all displays if any input method window has focus.
- for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
- final DisplayContent displayContent = mRoot.mChildren.get(i);
- if (displayContent.inputMethodClientHasFocus(client)) {
- return true;
+ @Override
+ public boolean inputMethodClientHasFocus(IInputMethodClient client) {
+ synchronized (mWindowMap) {
+ // Check all displays if any input method window has focus.
+ for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent displayContent = mRoot.mChildren.get(i);
+ if (displayContent.inputMethodClientHasFocus(client)) {
+ return true;
+ }
}
- }
- // Okay, how about this... what is the current focus?
- // It seems in some cases we may not have moved the IM
- // target window, such as when it was in a pop-up window,
- // so let's also look at the current focus. (An example:
- // go to Gmail, start searching so the keyboard goes up,
- // press home. Sometimes the IME won't go down.)
- // Would be nice to fix this more correctly, but it's
- // way at the end of a release, and this should be good enough.
- if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
- && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
- return true;
+ // Okay, how about this... what is the current focus?
+ // It seems in some cases we may not have moved the IM
+ // target window, such as when it was in a pop-up window,
+ // so let's also look at the current focus. (An example:
+ // go to Gmail, start searching so the keyboard goes up,
+ // press home. Sometimes the IME won't go down.)
+ // Would be nice to fix this more correctly, but it's
+ // way at the end of a release, and this should be good enough.
+ if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
+ && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
+ return true;
+ }
}
+ return false;
}
- return false;
- }
@Override
public int getDisplayIdForWindow(IBinder windowToken) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index fec803960012..979149a854cb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1176,15 +1176,17 @@ class WindowStateAnimator {
if (mIsWallpaper) {
w.dispatchWallpaperVisibility(true);
}
- // This draw means the difference between unique content and mirroring.
- // Run another pass through performLayout to set mHasContent in the
- // LogicalDisplay.
- mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- FINISH_LAYOUT_REDO_ANIM);
- if (DEBUG_LAYOUT_REPEATS) {
- mService.mWindowPlacerLocked.debugLayoutRepeats(
- "showSurfaceRobustlyLocked " + w,
- mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+ if (!w.getDisplayContent().getLastHasContent()) {
+ // This draw means the difference between unique content and mirroring.
+ // Run another pass through performLayout to set mHasContent in the
+ // LogicalDisplay.
+ mAnimator.setPendingLayoutChanges(w.getDisplayId(),
+ FINISH_LAYOUT_REDO_ANIM);
+ if (DEBUG_LAYOUT_REPEATS) {
+ mService.mWindowPlacerLocked.debugLayoutRepeats(
+ "showSurfaceRobustlyLocked " + w,
+ mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+ }
}
} else {
w.setOrientationChanging(false);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 233874475d9c..f6e5601dc4f7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -69,7 +69,6 @@ import org.mockito.invocation.InvocationOnMock;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityRecordTests extends ActivityTestsBase {
- private ActivityTaskManagerService mService;
private TestActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
@@ -79,10 +78,10 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+ setupActivityTaskManagerService();
+ mStack = mSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
mActivity = new ActivityBuilder(mService).setTask(mTask).build();
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 1aa80c884eeb..0345a81b5bec 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -64,8 +64,6 @@ import java.util.ArrayList;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackSupervisorTests extends ActivityTestsBase {
- private ActivityTaskManagerService mService;
- private ActivityStackSupervisor mSupervisor;
private ActivityStack mFullscreenStack;
@Before
@@ -73,8 +71,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mSupervisor = mService.mStackSupervisor;
+ setupActivityTaskManagerService();
mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 95f8fd177075..ab814ee15df0 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -60,8 +60,6 @@ import org.junit.runner.RunWith;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackTests extends ActivityTestsBase {
- private ActivityTaskManagerService mService;
- private ActivityStackSupervisor mSupervisor;
private ActivityDisplay mDefaultDisplay;
private ActivityStack mStack;
private TaskRecord mTask;
@@ -71,9 +69,8 @@ public class ActivityStackTests extends ActivityTestsBase {
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mSupervisor = mService.mStackSupervisor;
- mDefaultDisplay = mService.mStackSupervisor.getDefaultDisplay();
+ setupActivityTaskManagerService();
+ mDefaultDisplay = mSupervisor.getDefaultDisplay();
mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index d032eb51c974..749403ea4013 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -32,26 +32,32 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
import static com.android.server.am.ActivityManagerService.ANIMATE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.WindowLayout;
@@ -65,28 +71,6 @@ import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.view.Gravity;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
-import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -106,7 +90,6 @@ import org.junit.runner.RunWith;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStarterTests extends ActivityTestsBase {
- private ActivityTaskManagerService mService;
private ActivityStarter mStarter;
private ActivityStartController mController;
private ActivityMetricsLogger mActivityMetricsLogger;
@@ -130,7 +113,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
+ setupActivityTaskManagerService();
mController = mock(ActivityStartController.class);
mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
clearInvocations(mActivityMetricsLogger);
@@ -323,7 +306,22 @@ public class ActivityStarterTests extends ActivityTestsBase {
}
}
- private ActivityStarter prepareStarter(int launchFlags) {
+ private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
+ return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
+ }
+
+ /**
+ * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
+ *
+ * @param launchFlags The intent flags to launch activity.
+ * @param mockGetLaunchStack Whether to mock {@link ActivityStackSupervisor#getLaunchStack} for
+ * always launching to the testing stack. Set to false when allowing
+ * the activity can be launched to any stack that is decided by real
+ * implementation.
+ * @return A {@link ActivityStarter} with default setup.
+ */
+ private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
+ boolean mockGetLaunchStack) {
// always allow test to start activity.
doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
@@ -343,11 +341,13 @@ public class ActivityStarterTests extends ActivityTestsBase {
// return task when created.
doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
- // direct starter to use spy stack.
- doReturn(stack).when(mService.mStackSupervisor)
- .getLaunchStack(any(), any(), any(), anyBoolean());
- doReturn(stack).when(mService.mStackSupervisor)
- .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+ if (mockGetLaunchStack) {
+ // Direct starter to use spy stack.
+ doReturn(stack).when(mService.mStackSupervisor)
+ .getLaunchStack(any(), any(), any(), anyBoolean());
+ doReturn(stack).when(mService.mStackSupervisor)
+ .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+ }
// Set up mock package manager internal and make sure no unmocked methods are called
PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class,
@@ -546,4 +546,84 @@ public class ActivityStarterTests extends ActivityTestsBase {
eq(ActivityBuilder.getDefaultComponent().getPackageName()), anyInt(), anyBoolean(),
any(), eq(false));
}
+
+ /**
+ * This test ensures that when starting an existing single task activity on secondary display
+ * which is not the top focused display, it should deliver new intent to the activity and not
+ * create a new stack.
+ */
+ @Test
+ public void testDeliverIntentToTopActivityOfNonTopDisplay() {
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetLaunchStack */);
+
+ // Create a secondary display at bottom.
+ final TestActivityDisplay secondaryDisplay = spy(addNewActivityDisplayAt(POSITION_BOTTOM));
+ final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ // Create an activity record on the top of secondary display.
+ final ComponentName componentName = ComponentName.createRelative(
+ DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_PACKAGE_NAME + ".ReusableActivity");
+ final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+ .setComponent(componentName)
+ .setStack(stack)
+ .build();
+ final ActivityRecord topActivityOnSecondaryDisplay = new ActivityBuilder(mService)
+ .setComponent(componentName)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setTask(taskRecord)
+ .build();
+
+ // Put an activity on default display as the top focused activity.
+ new ActivityBuilder(mService).setCreateTask(true).build();
+
+ // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
+ // on secondary display.
+ final ActivityOptions options = ActivityOptions.makeBasic()
+ .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
+ .setIntent(topActivityOnSecondaryDisplay.intent)
+ .setActivityOptions(options.toBundle())
+ .execute();
+
+ // Ensure result is delivering intent to top.
+ assertEquals(START_DELIVERED_TO_TOP, result);
+
+ // Ensure secondary display only creates one stack.
+ verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
+ }
+
+ /**
+ * This test ensures that a reused top activity in the top focused stack is able to be
+ * reparented to another display.
+ */
+ @Test
+ public void testReparentTopFocusedActivityToSecondaryDisplay() {
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetLaunchStack */);
+
+ // Create a secondary display at bottom.
+ final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
+ secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+
+ // Put an activity on default display as the top focused activity.
+ final ActivityRecord topActivity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .build();
+
+ // Start activity with the same intent as {@code topActivity} on secondary display.
+ final ActivityOptions options = ActivityOptions.makeBasic()
+ .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
+ .setIntent(topActivity.intent)
+ .setActivityOptions(options.toBundle())
+ .execute();
+
+ // Ensure the activity is moved to secondary display.
+ assertEquals(secondaryDisplay, topActivity.getDisplay());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index bb8e5c555481..9d09f5c44a28 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -56,11 +57,14 @@ import android.content.pm.IPackageManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.testing.DexmakerShareClassLoaderRule;
+import android.view.Display;
+import android.view.DisplayInfo;
import androidx.test.InstrumentationRegistry;
@@ -86,6 +90,8 @@ import java.util.List;
public class ActivityTestsBase {
private static boolean sOneTimeSetupDone = false;
+ private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
+
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
@@ -93,6 +99,9 @@ public class ActivityTestsBase {
private final Context mContext = InstrumentationRegistry.getContext();
private HandlerThread mHandlerThread;
+ ActivityTaskManagerService mService;
+ ActivityStackSupervisor mSupervisor;
+
// Default package name
static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
@@ -122,6 +131,11 @@ public class ActivityTestsBase {
return atm;
}
+ void setupActivityTaskManagerService() {
+ mService = createActivityTaskManagerService();
+ mSupervisor = mService.mStackSupervisor;
+ }
+
ActivityManagerService createActivityManagerService() {
final TestActivityTaskManagerService atm =
spy(new TestActivityTaskManagerService(mContext));
@@ -134,6 +148,18 @@ public class ActivityTestsBase {
return am;
}
+ /** Creates a {@link TestActivityDisplay}. */
+ TestActivityDisplay createNewActivityDisplay() {
+ return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
+ }
+
+ /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
+ TestActivityDisplay addNewActivityDisplayAt(int position) {
+ final TestActivityDisplay display = createNewActivityDisplay();
+ mSupervisor.addChild(display, position);
+ return display;
+ }
+
void setupActivityManagerService(
TestActivityManagerService am, TestActivityTaskManagerService atm) {
atm.setActivityManagerService(am);
@@ -173,6 +199,7 @@ public class ActivityTestsBase {
private boolean mCreateTask;
private ActivityStack mStack;
private int mActivityFlags;
+ private int mLaunchMode;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -198,6 +225,11 @@ public class ActivityTestsBase {
return this;
}
+ ActivityBuilder setLaunchMode(int launchMode) {
+ mLaunchMode = launchMode;
+ return this;
+ }
+
ActivityBuilder setStack(ActivityStack stack) {
mStack = stack;
return this;
@@ -233,6 +265,7 @@ public class ActivityTestsBase {
aInfo.applicationInfo.packageName = mComponent.getPackageName();
aInfo.applicationInfo.uid = mUid;
aInfo.flags |= mActivityFlags;
+ aInfo.launchMode = mLaunchMode;
final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
0 /* launchedFromPid */, 0, null, intent, null,
@@ -500,7 +533,7 @@ public class ActivityTestsBase {
@Override
public void initialize() {
super.initialize();
- mDisplay = spy(new TestActivityDisplay(this, DEFAULT_DISPLAY));
+ mDisplay = spy(TestActivityDisplay.create(this, DEFAULT_DISPLAY));
addChild(mDisplay, ActivityDisplay.POSITION_TOP);
}
@@ -516,10 +549,20 @@ public class ActivityTestsBase {
}
protected static class TestActivityDisplay extends ActivityDisplay {
-
private final ActivityStackSupervisor mSupervisor;
- TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
- super(supervisor, displayId);
+
+ static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
+ if (displayId == DEFAULT_DISPLAY) {
+ return new TestActivityDisplay(supervisor,
+ supervisor.mDisplayManager.getDisplay(displayId));
+ }
+ final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+ return new TestActivityDisplay(supervisor, display);
+ }
+
+ TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
+ super(supervisor, display);
// Normally this comes from display-properties as exposed by WM. Without that, just
// hard-code to FULLSCREEN for tests.
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 519521429f1b..70cfad1d0f2f 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -870,8 +870,8 @@ public class RecentTasksTest extends ActivityTestsBase {
@Override
public void initialize() {
super.initialize();
- mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
- mOtherDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
+ mDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY);
+ mOtherDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY + 1);
addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
addChild(mDisplay, ActivityDisplay.POSITION_TOP);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
index d56c6a6d7403..aa3046fb694c 100644
--- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
@@ -51,7 +51,6 @@ import java.util.ArrayList;
public class RunningTasksTest extends ActivityTestsBase {
private Context mContext = InstrumentationRegistry.getContext();
- private ActivityTaskManagerService mService;
private RunningTasks mRunningTasks;
@@ -60,21 +59,20 @@ public class RunningTasksTest extends ActivityTestsBase {
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
+ setupActivityTaskManagerService();
mRunningTasks = new RunningTasks();
}
@Test
public void testCollectTasksByLastActiveTime() throws Exception {
// Create a number of stacks with tasks (of incrementing active time)
- final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
final ArrayList<ActivityDisplay> displays = new ArrayList<>();
- final ActivityDisplay display = new TestActivityDisplay(supervisor, DEFAULT_DISPLAY);
+ final ActivityDisplay display = TestActivityDisplay.create(mSupervisor, DEFAULT_DISPLAY);
displays.add(display);
final int numStacks = 2;
for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) {
- final ActivityStack stack = new TestActivityStack(display, stackIndex, supervisor,
+ final ActivityStack stack = new TestActivityStack(display, stackIndex, mSupervisor,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true);
display.addChild(stack, POSITION_BOTTOM);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 95d4a15b5fdb..659c6e7aeed3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -20,6 +20,7 @@ import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAG
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -34,6 +35,7 @@ import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -47,6 +49,9 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -68,7 +73,9 @@ import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
public class ManagedServicesTest extends UiServiceTestCase {
@@ -113,7 +120,12 @@ public class ManagedServicesTest extends UiServiceTestCase {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
when(mUm.getUsers()).thenReturn(users);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
+ IntArray profileIds = new IntArray();
+ profileIds.add(0);
+ profileIds.add(11);
+ profileIds.add(10);
+ profileIds.add(12);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
mExpectedPrimaryPackages = new ArrayMap<>();
mExpectedPrimaryPackages.put(0, "this.is.a.package.name:another.package");
@@ -165,12 +177,12 @@ public class ManagedServicesTest extends UiServiceTestCase {
@Test
public void testBackupAndRestore_migration_preO() throws Exception {
- ArrayMap backupPrimaryPackages = new ArrayMap<>();
+ ArrayMap<Integer, String> backupPrimaryPackages = new ArrayMap<>();
backupPrimaryPackages.put(0, "backup.0:backup:0a");
backupPrimaryPackages.put(10, "10.backup");
backupPrimaryPackages.put(11, "eleven");
backupPrimaryPackages.put(12, "");
- ArrayMap backupPrimaryComponentNames = new ArrayMap<>();
+ ArrayMap<Integer, String> backupPrimaryComponentNames = new ArrayMap<>();
backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b");
backupPrimaryComponentNames.put(10, "again/M1");
backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana");
@@ -179,11 +191,11 @@ public class ManagedServicesTest extends UiServiceTestCase {
backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages);
backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames);
- ArrayMap backupSecondaryComponentNames = new ArrayMap<>();
+ ArrayMap<Integer, String> backupSecondaryComponentNames = new ArrayMap<>();
backupSecondaryComponentNames.put(0, "secondary.1/component.Name");
backupSecondaryComponentNames.put(10,
"this.is.another.package.backup/with.Component:component.backup/2");
- ArrayMap backupSecondaryPackages = new ArrayMap<>();
+ ArrayMap<Integer, String> backupSecondaryPackages = new ArrayMap<>();
backupSecondaryPackages.put(0, "");
backupSecondaryPackages.put(10,
"this.is.another.package.backup:package.backup");
@@ -368,7 +380,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
serializer.endDocument();
serializer.flush();
- for (int userId : mUserProfiles.getCurrentProfileIds()) {
+ for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) {
List<String> expected =
stringToList(mExpectedPrimary.get(approvalLevel).get(userId));
List<String> actual = stringToList(Settings.Secure.getStringForUser(
@@ -633,7 +645,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
- public void testGetAllowedComponents() throws Exception {
+ public void testGetAllowedComponentsByUser() throws Exception {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
APPROVAL_BY_COMPONENT);
loadXml(service);
@@ -708,6 +720,145 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertTrue(services.isSameUser(service, 10));
}
+ @Test
+ public void testGetAllowedComponents() throws Exception {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ loadXml(service);
+
+ SparseArray<ArraySet<ComponentName>> expected = new SparseArray<>();
+
+ ArraySet<ComponentName> expected10 = new ArraySet<>();
+ expected10.add(ComponentName.unflattenFromString("this.is.another.package/M1"));
+ expected10.add(ComponentName.unflattenFromString("this.is.another.package/with.Component"));
+ expected10.add(ComponentName.unflattenFromString("component/2"));
+ expected10.add(ComponentName.unflattenFromString("package/component2"));
+ expected.put(10, expected10);
+ ArraySet<ComponentName> expected0 = new ArraySet<>();
+ expected0.add(ComponentName.unflattenFromString("secondary/component.Name"));
+ expected0.add(ComponentName.unflattenFromString("this.is.a.package.name/Ba"));
+ expected0.add(ComponentName.unflattenFromString("another.package/B1"));
+ expected.put(0, expected0);
+ ArraySet<ComponentName> expected12 = new ArraySet<>();
+ expected12.add(ComponentName.unflattenFromString("bananas!/Bananas!"));
+ expected.put(12, expected12);
+ expected.put(11, new ArraySet<>());
+
+ SparseArray<ArraySet<ComponentName>> actual =
+ service.getAllowedComponents(mUserProfiles.getCurrentProfileIds());
+
+ assertContentsInAnyOrder(expected, actual);
+ }
+
+ @Test
+ public void testPopulateComponentsToUnbind_forceRebind() {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ IInterface iInterface = mock(IInterface.class);
+ when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+ ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
+ mock(ServiceConnection.class), 26);
+ ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
+ mock(ServiceConnection.class), 26);
+ Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+ removableBoundServices.add(service0);
+ removableBoundServices.add(service10);
+
+ SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
+ Set<ComponentName> allowed0 = new ArraySet<>();
+ allowed0.add(ComponentName.unflattenFromString("a/a"));
+ allowedComponentsToBind.put(0, allowed0);
+ Set<ComponentName> allowed10 = new ArraySet<>();
+ allowed10.add(ComponentName.unflattenFromString("b/b"));
+ allowedComponentsToBind.put(10, allowed10);
+
+ SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+ service.populateComponentsToUnbind(true, removableBoundServices, allowedComponentsToBind,
+ componentsToUnbind);
+
+ assertEquals(2, componentsToUnbind.size());
+ assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("a/a")));
+ assertTrue(componentsToUnbind.get(10).contains(ComponentName.unflattenFromString("b/b")));
+ }
+
+ @Test
+ public void testPopulateComponentsToUnbind() {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ IInterface iInterface = mock(IInterface.class);
+ when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+ ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
+ mock(ServiceConnection.class), 26);
+ ManagedServices.ManagedServiceInfo service0a = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("c/c"), 0, false,
+ mock(ServiceConnection.class), 26);
+ ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
+ mock(ServiceConnection.class), 26);
+ Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+ removableBoundServices.add(service0);
+ removableBoundServices.add(service0a);
+ removableBoundServices.add(service10);
+
+ SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
+ Set<ComponentName> allowed0 = new ArraySet<>();
+ allowed0.add(ComponentName.unflattenFromString("a/a"));
+ allowedComponentsToBind.put(0, allowed0);
+ Set<ComponentName> allowed10 = new ArraySet<>();
+ allowed10.add(ComponentName.unflattenFromString("b/b"));
+ allowedComponentsToBind.put(10, allowed10);
+
+ SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+ service.populateComponentsToUnbind(false, removableBoundServices, allowedComponentsToBind,
+ componentsToUnbind);
+
+ assertEquals(1, componentsToUnbind.size());
+ assertEquals(1, componentsToUnbind.get(0).size());
+ assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("c/c")));
+ }
+
+ @Test
+ public void populateComponentsToBind() {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
+ ArraySet<ComponentName> allowed0 = new ArraySet<>();
+ allowed0.add(ComponentName.unflattenFromString("a/a"));
+ approvedComponentsByUser.put(0, allowed0);
+ ArraySet<ComponentName> allowed10 = new ArraySet<>();
+ allowed10.add(ComponentName.unflattenFromString("b/b"));
+ allowed10.add(ComponentName.unflattenFromString("c/c"));
+ approvedComponentsByUser.put(10, allowed10);
+ ArraySet<ComponentName> allowed15 = new ArraySet<>();
+ allowed15.add(ComponentName.unflattenFromString("d/d"));
+ approvedComponentsByUser.put(15, allowed15);
+
+ IntArray users = new IntArray();
+ users.add(10);
+ users.add(0);
+
+ SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+
+ service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);
+
+ assertEquals(2, componentsToBind.size());
+ assertEquals(1, componentsToBind.get(0).size());
+ assertTrue(componentsToBind.get(0).contains(ComponentName.unflattenFromString("a/a")));
+ assertEquals(2, componentsToBind.get(10).size());
+ assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("b/b")));
+ assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
+ }
+
private void loadXml(ManagedServices service) throws Exception {
final StringBuffer xml = new StringBuffer();
xml.append("<" + service.getConfig().xmlTag + ">\n");
@@ -775,7 +926,8 @@ public class ManagedServicesTest extends UiServiceTestCase {
ManagedServices.ENABLED_SERVICES_SEPARATOR)));
}
- private void assertContentsInAnyOrder(List<?> expected, List<?> actual) {
+ private void assertContentsInAnyOrder(Collection<?> expected, Collection<?> actual) {
+ assertNotNull(actual);
assertEquals(expected.size(), actual.size());
for (Object o : expected) {
@@ -787,6 +939,21 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
}
+ private void assertContentsInAnyOrder(SparseArray<ArraySet<ComponentName>> expected,
+ SparseArray<ArraySet<ComponentName>> actual) throws Exception {
+ assertEquals(expected.size(), actual.size());
+
+ for (int i = 0; i < expected.size(); i++) {
+ int key = expected.keyAt(i);
+ assertTrue(actual.indexOfKey(key) >= 0);
+ try {
+ assertContentsInAnyOrder(expected.valueAt(i), actual.get(key));
+ } catch (Throwable t) {
+ throw new Exception("Error validating " + key, t);
+ }
+ }
+ }
+
private void verifyExpectedBoundEntries(ManagedServices service, boolean primary)
throws Exception {
ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel)
@@ -920,7 +1087,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
@Override
protected boolean checkType(IInterface service) {
- return false;
+ return true;
}
@Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index f9a4f784bf4f..1de1e4ef8b9f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -33,6 +33,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.UserManager;
+import android.util.IntArray;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -103,7 +104,12 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
}
when(mUm.getUsers()).thenReturn(users);
when(mUm.getUsers(anyBoolean())).thenReturn(users);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
+ IntArray profileIds = new IntArray();
+ profileIds.add(0);
+ profileIds.add(11);
+ profileIds.add(10);
+ profileIds.add(12);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 88c6fcf138cf..b955e56c80a8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -32,6 +32,7 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.IntArray;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -235,18 +236,22 @@ public class SnoozeHelperTest extends UiServiceTestCase {
mSnoozeHelper.snooze(r2, 1000);
mSnoozeHelper.snooze(r3, 1000);
mSnoozeHelper.snooze(r4, 1000);
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(
- new int[] {UserHandle.USER_SYSTEM});
+ IntArray profileIds = new IntArray();
+ profileIds.add(UserHandle.USER_SYSTEM);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
assertEquals(3, mSnoozeHelper.getSnoozed().size());
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(
- new int[] {UserHandle.USER_CURRENT});
+ profileIds = new IntArray();
+ profileIds.add(UserHandle.USER_CURRENT);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
assertEquals(1, mSnoozeHelper.getSnoozed().size());
}
@Test
public void testGetSnoozedByUser_managedProfiles() throws Exception {
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(
- new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT});
+ IntArray profileIds = new IntArray();
+ profileIds.add(UserHandle.USER_CURRENT);
+ profileIds.add(UserHandle.USER_SYSTEM);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
@@ -273,8 +278,9 @@ public class SnoozeHelperTest extends UiServiceTestCase {
@Test
public void repostGroupSummary_repostsSummary() throws Exception {
- when(mUserProfiles.getCurrentProfileIds()).thenReturn(
- new int[] {UserHandle.USER_SYSTEM});
+ IntArray profileIds = new IntArray();
+ profileIds.add(UserHandle.USER_SYSTEM);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
NotificationRecord r = getNotificationRecord(
"pkg", 1, "one", UserHandle.SYSTEM, "group1", true);
NotificationRecord r2 = getNotificationRecord(
diff --git a/startop/scripts/app_startup/force_compiler_filter b/startop/scripts/app_startup/force_compiler_filter
index 78e915bb4d53..08f983d92bea 100755
--- a/startop/scripts/app_startup/force_compiler_filter
+++ b/startop/scripts/app_startup/force_compiler_filter
@@ -100,36 +100,6 @@ parse_arguments() {
fi
}
-get_activity_name() {
- local package="$1"
- local action_key="android.intent.action.MAIN:"
-
- local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
- verbose_print $activity_line
- IFS="/" read -a array <<< "$activity_line"
- local activity_name="${array[1]}"
- echo "$activity_name"
- #adb shell am start "$package/$activity_name"
-}
-
-remote_pidof() {
- local procname="$1"
- adb shell ps | grep "$procname" | awk '{print $2;}'
-}
-
-remote_pkill() {
- local procname="$1"
- shift
-
- local the_pids=$(remote_pidof "$procname")
- local pid
-
- for pid in $the_pids; do
- verbose_print adb shell kill "$@" "$pid"
- adb shell kill "$@" "$pid"
- done
-}
-
force_package_compilation() {
local arg_compiler_filter="$1"
local arg_package="$2"
@@ -150,13 +120,13 @@ main() {
# screen needs to be unlocked in order to run an app
"$DIR"/unlock_screen
- am_output="$(adb shell am start -S -W "$package"/"$activity")"
+ local output=$("$DIR"/launch_application "$package" "$activity")
if [[ $? -ne 0 ]]; then
- echo "am start failed" >&2
+ echo "launching application failed" >&2
exit 1
fi
- verbose_print "$am_output"
+ verbose_print "$output"
# give some time for app startup to complete.
# this is supposed to be an upper bound for measuring startup time.
sleep "$wait_time"
diff --git a/startop/scripts/app_startup/launch_application b/startop/scripts/app_startup/launch_application
index bc4ec51d6d08..8a68e5016190 100755
--- a/startop/scripts/app_startup/launch_application
+++ b/startop/scripts/app_startup/launch_application
@@ -20,6 +20,12 @@ source "$DIR/lib/common"
launch_application() {
local package="$1"
local activity="$2"
+
+ # if there's any $s inside of the activity name, it needs to be escaped to \$.
+ # example '.app.honeycomb.Shell$HomeActivity'
+ # if the $ is not escaped, adb shell will try to evaluate $HomeActivity to a variable.
+ activity=${activity//\$/\\$}
+
local am_output="$(adb shell am start -S -W "$package"/"$activity")"
verbose_print adb shell am start -S -W "$package"/"$activity"
if [[ $? -ne 0 ]]; then
diff --git a/startop/scripts/app_startup/lib/common b/startop/scripts/app_startup/lib/common
index 4d5a53e4bb0c..043d8550b64b 100755
--- a/startop/scripts/app_startup/lib/common
+++ b/startop/scripts/app_startup/lib/common
@@ -12,3 +12,42 @@ verbose_print() {
echo "$@" >&2
fi
}
+
+remote_pidof() {
+ local procname="$1"
+ adb shell ps | grep "$procname" | awk '{print $2;}'
+}
+
+remote_pkill() {
+ local procname="$1"
+ shift
+
+ local the_pids=$(remote_pidof "$procname")
+ local pid
+
+ for pid in $the_pids; do
+ verbose_print adb shell kill "$@" "$pid"
+ adb shell kill "$@" "$pid"
+ done
+}
+
+get_activity_name() {
+ local package="$1"
+ local action_key="android.intent.action.MAIN:"
+
+ # Example query-activities output being parsed:
+ #
+ # Activity #14:
+ # priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true
+ # com.google.android.videos/com.google.android.youtube.videos.EntryPoint
+ # Activity #15:
+ # priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true
+ # com.google.android.youtube/.app.honeycomb.Shell$HomeActivity
+
+ # Given package 'com.google.android.youtube' return '.app.honeycomb.Shell$HomeActivity'
+
+ local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package/")"
+ IFS="/" read -a array <<< "$activity_line"
+ local activity_name="${array[1]}"
+ echo "$activity_name"
+}
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
index ce63ff958613..56bffa85eb90 100755
--- a/startop/scripts/app_startup/run_app_with_prefetch
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -111,18 +111,6 @@ echo_to_output_file() {
echo "$@"
}
-get_activity_name() {
- local package="$1"
- local action_key="android.intent.action.MAIN:"
-
- local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
- #echo $activity_line
- IFS="/" read -a array <<< "$activity_line"
- local activity_name="${array[1]}"
- echo "$activity_name"
- #adb shell am start "$package/$activity_name"
-}
-
find_package_path() {
local pkg="$1"
@@ -133,11 +121,6 @@ find_package_path() {
echo "$res"
}
-remote_pkill() {
- local what="$1"
- adb shell "for i in $(pid $what); do kill \$i; done"
-}
-
# Main entry point
if [[ $# -eq 0 ]]; then
usage
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ffbe7d34e5e7..7506d006122b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1070,6 +1070,16 @@ public class CarrierConfigManager {
/**
* 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 +1087,15 @@ public class CarrierConfigManager {
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
@@ -2263,6 +2282,7 @@ public class CarrierConfigManager {
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);
@@ -2272,7 +2292,7 @@ public class CarrierConfigManager {
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);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b01d41948c3b..e9423f75c9e1 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -60,6 +60,7 @@ import java.util.ArrayList;
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;
@@ -1811,6 +1812,19 @@ public class SubscriptionManager {
*/
@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);
@@ -1822,6 +1836,11 @@ public class SubscriptionManager {
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);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index 6bf22a05beec..8015b07fa024 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.GsmAlphabet;
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 @@ public class GsmSmsCbMessage {
* 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/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 4790b75d9630..6b3df94063bf 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 @@ public class IccUtils {
* 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 @@ public class IccUtils {
}
/**
+ * 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 @@ public class IccUtils {
}
/**
- * 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/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
index 1b638747ee09..6500428253f6 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
@@ -16,24 +16,27 @@
package com.android.tests.sysmem.host;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
/**
* Critical user journeys with which to exercise the system, driven from the
* host.
*/
public class Cujs {
- private ITestDevice mDevice;
+ private Device mDevice;
- public Cujs(ITestDevice device) {
+ public Cujs(Device device) {
this.mDevice = device;
}
/**
* Runs the critical user journeys.
*/
- public void run() throws DeviceNotAvailableException {
+ public void run() throws TestException {
+ // Do an explicit GC in the system server process as part of the test
+ // case to reduce GC-related sources of noise.
+ // SIGUSR1 = 10 is the magic signal to trigger the GC.
+ int pid = mDevice.getPidForProcess("system_server");
+ mDevice.executeShellCommand("kill -10 " + pid);
+
// Invoke the Device Cujs instrumentation to run the cujs.
// TODO: Consider exercising the system in other interesting ways as
// well.
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java
new file mode 100644
index 000000000000..03503cec5fec
--- /dev/null
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.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 com.android.tests.sysmem.host;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+/**
+ * Wrapper around ITestDevice exposing useful device functions.
+ */
+class Device {
+
+ private ITestDevice mDevice;
+
+ Device(ITestDevice device) {
+ mDevice = device;
+ }
+
+ /**
+ * Execute a shell command and return the output as a string.
+ */
+ public String executeShellCommand(String command) throws TestException {
+ try {
+ return mDevice.executeShellCommand(command);
+ } catch (DeviceNotAvailableException e) {
+ throw new TestException(e);
+ }
+ }
+
+ /**
+ * Enable adb root
+ */
+ public void enableAdbRoot() throws TestException {
+ try {
+ mDevice.enableAdbRoot();
+ } catch (DeviceNotAvailableException e) {
+ throw new TestException(e);
+ }
+ }
+
+ /**
+ * Returns the pid for the process with the given name.
+ */
+ public int getPidForProcess(String name) throws TestException {
+ String psout = executeShellCommand("ps -A -o PID,CMD");
+ Scanner sc = new Scanner(psout);
+ try {
+ // ps output is of the form:
+ // PID CMD
+ // 1 init
+ // 2 kthreadd
+ // ...
+ // 9693 ps
+ sc.nextLine();
+ while (sc.hasNextLine()) {
+ int pid = sc.nextInt();
+ String cmd = sc.next();
+
+ if (name.equals(cmd)) {
+ return pid;
+ }
+ }
+ } catch (InputMismatchException e) {
+ throw new TestException("unexpected ps output format: " + psout, e);
+ }
+
+ throw new TestException("failed to get pid for process " + name);
+ }
+}
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
index cfd598da1a5f..48b7f393d0a3 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
@@ -16,7 +16,6 @@
package com.android.tests.sysmem.host;
-import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
@@ -27,8 +26,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
-
/**
* Runs a system memory test.
*/
@@ -44,8 +41,9 @@ public class MemoryTest implements IDeviceTest {
private Cujs mCujs;
@Override
- public void setDevice(ITestDevice device) {
- mTestDevice = device;
+ public void setDevice(ITestDevice testDevice) {
+ mTestDevice = testDevice;
+ Device device = new Device(testDevice);
mMetrics = new Metrics(device, testMetrics, testLogs);
mCujs = new Cujs(device);
}
@@ -56,14 +54,13 @@ public class MemoryTest implements IDeviceTest {
}
// Invoke a single iteration of running the cujs.
- private void runCujs() throws DeviceNotAvailableException {
+ private void runCujs() throws TestException {
mCujs.run();
mIterations++;
}
// Sample desired memory.
- private void sample()
- throws DeviceNotAvailableException, IOException, Metrics.MetricsException {
+ private void sample() throws TestException {
mMetrics.sample(String.format("%03d", mIterations));
}
@@ -71,7 +68,7 @@ public class MemoryTest implements IDeviceTest {
* Runs the memory tests.
*/
@Test
- public void run() throws Exception {
+ public void run() throws TestException {
sample(); // Sample before running cujs
runCujs();
sample(); // Sample after first iteration of cujs
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
index 70bc22c485e1..b408a81d8f93 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
@@ -16,8 +16,6 @@
package com.android.tests.sysmem.host;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
@@ -34,24 +32,11 @@ import java.util.Scanner;
*/
class Metrics {
- private ITestDevice mDevice;
+ private Device mDevice;
private TestMetrics mMetrics;
private TestLogData mLogs;
/**
- * Exception thrown in case of error sampling metrics.
- */
- public static class MetricsException extends Exception {
- MetricsException(String msg) {
- super(msg);
- }
-
- MetricsException(String msg, Exception cause) {
- super(msg, cause);
- }
- }
-
- /**
* Constructs a metrics instance that will output high level metrics and
* more detailed breakdowns using the given <code>metrics</code> and
* <code>logs</code> objects.
@@ -60,7 +45,7 @@ class Metrics {
* @param metrics where to log the high level metrics when taking a sample
* @param logs where to log detailed breakdowns when taking a sample
*/
- Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) {
+ Metrics(Device device, TestMetrics metrics, TestLogData logs) {
this.mDevice = device;
this.mMetrics = metrics;
this.mLogs = logs;
@@ -69,43 +54,17 @@ class Metrics {
/**
* Writes the given <code>text</code> to a log with the given label.
*/
- private void logText(String label, String text) throws IOException {
- File file = File.createTempFile(label, "txt");
- PrintStream ps = new PrintStream(file);
- ps.print(text);
- try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
- mLogs.addTestLog(label, LogDataType.TEXT, dataStream);
- }
- }
-
- /**
- * Returns the pid for the process with the given name.
- */
- private int getPidForProcess(String name)
- throws DeviceNotAvailableException, IOException, MetricsException {
- String psout = mDevice.executeShellCommand("ps -A -o PID,CMD");
- Scanner sc = new Scanner(psout);
+ private void logText(String label, String text) throws TestException {
try {
- // ps output is of the form:
- // PID CMD
- // 1 init
- // 2 kthreadd
- // ...
- // 9693 ps
- sc.nextLine();
- while (sc.hasNextLine()) {
- int pid = sc.nextInt();
- String cmd = sc.next();
-
- if (name.equals(cmd)) {
- return pid;
- }
+ File file = File.createTempFile(label, "txt");
+ PrintStream ps = new PrintStream(file);
+ ps.print(text);
+ try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
+ mLogs.addTestLog(label, LogDataType.TEXT, dataStream);
}
- } catch (InputMismatchException e) {
- throw new MetricsException("unexpected ps output format: " + psout, e);
+ } catch (IOException e) {
+ throw new TestException(e);
}
-
- throw new MetricsException("failed to get pid for process " + name);
}
/**
@@ -116,11 +75,11 @@ class Metrics {
*
* @param label prefix to use for metrics and logs output for this sample.
*/
- void sample(String label) throws DeviceNotAvailableException, IOException, MetricsException {
+ void sample(String label) throws TestException {
// adb root access is required to get showmap
mDevice.enableAdbRoot();
- int pid = getPidForProcess("system_server");
+ int pid = mDevice.getPidForProcess("system_server");
// Read showmap for system server and add it as a test log
String showmap = mDevice.executeShellCommand("showmap " + pid);
@@ -146,7 +105,7 @@ class Metrics {
mMetrics.addTestMetric(label + ".system_server.rss", Long.toString(rss));
mMetrics.addTestMetric(label + ".system_server.pss", Long.toString(pss));
} catch (InputMismatchException e) {
- throw new MetricsException("unexpected showmap format", e);
+ throw new TestException("unexpected showmap format", e);
}
// Run debuggerd -j to get GC stats for system server and add it as a
diff --git a/core/res/res/values-mcc262-mnc02/strings.xml b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java
index 2b8940195ee3..dc3b68f4b455 100644
--- a/core/res/res/values-mcc262-mnc02/strings.xml
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2017, Google Inc.
+/*
+ * 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
+ * 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,
@@ -15,13 +13,23 @@
* 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">
+package com.android.tests.sysmem.host;
+
+/**
+ * Exception thrown in case of unexpected error encountered when executing the
+ * test.
+ */
+class TestException extends Exception {
+ TestException(Exception cause) {
+ super(cause);
+ }
+
+ TestException(String msg) {
+ super(msg);
+ }
- <!-- 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>
+ TestException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 2ecf25b751b6..c02ca211a194 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -83,6 +83,7 @@ cc_library_host_static {
"compile/Pseudolocalizer.cpp",
"compile/XmlIdCollector.cpp",
"configuration/ConfigurationParser.cpp",
+ "dump/DumpManifest.cpp",
"filter/AbiFilter.cpp",
"filter/ConfigFilter.cpp",
"format/Archive.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index a73d56c8f951..6d78990e4636 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -255,7 +255,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
}
std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path,
- IDiagnostics* diag) {
+ IDiagnostics* diag) const {
io::IFile* file = apk_->FindFile(file_path);
if (file == nullptr) {
diag->Error(DiagMessage() << "failed to find file");
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index dcb085aa2b0b..84c57c14474a 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -111,7 +111,7 @@ class LoadedApk {
IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
/** Loads the file as an xml document. */
- std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag);
+ std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag) const;
private:
DISALLOW_COPY_AND_ASSIGN(LoadedApk);
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 5cb30b6f5db2..91e39771e490 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -223,6 +223,12 @@ int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
return 1;
}
+ ResourceTable* table = loaded_apk->GetResourceTable();
+ if (!table) {
+ diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+ return 1;
+ }
+
io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
Printer printer(&fout);
@@ -233,7 +239,7 @@ int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
// Insert the configurations into a set in order to keep every configuarion seen
std::set<ConfigDescription, decltype(compare)> configs(compare);
- for (auto& package : loaded_apk->GetResourceTable()->packages) {
+ for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
for (auto& value : entry->values) {
@@ -267,10 +273,15 @@ int DumpStringsCommand::Action(const std::vector<std::string>& args) {
return 1;
}
+ ResourceTable* table = loaded_apk->GetResourceTable();
+ if (!table) {
+ diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+ return 1;
+ }
+
// Load the run-time xml string pool using the flattened data
BigBuffer buffer(4096);
- StringPool::FlattenUtf8(&buffer, loaded_apk->GetResourceTable()->string_pool,
- context.GetDiagnostics());
+ StringPool::FlattenUtf8(&buffer, table->string_pool, context.GetDiagnostics());
auto data = buffer.to_string();
android::ResStringPool pool(data.data(), data.size(), false);
Debug::DumpResStringPool(&pool, &printer);
@@ -304,7 +315,13 @@ int DumpTableCommand::Action(const std::vector<std::string>& args) {
printer.Println("Binary APK");
}
- Debug::PrintTable(*loaded_apk->GetResourceTable(), print_options, &printer);
+ ResourceTable* table = loaded_apk->GetResourceTable();
+ if (!table) {
+ diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+ return 1;
+ }
+
+ Debug::PrintTable(*table, print_options, &printer);
}
return 0;
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 0724d6203e8f..9ec820d89596 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -19,6 +19,7 @@
#include "Command.h"
#include "Debug.h"
+#include "dump/DumpManifest.h"
namespace aapt {
@@ -133,8 +134,10 @@ class DumpCommand : public Command {
public:
explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) {
AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_));
+ AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(diag_));
AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_));
AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(diag_));
+ AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(diag_));
AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_));
AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_));
AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_));
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 119f56a5013c..13c10478ba3e 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1842,9 +1842,15 @@ class Linker {
} else {
// Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
// equal to the minSdk.
+ const size_t origConstraintSize = options_.split_constraints.size();
options_.split_constraints =
AdjustSplitConstraintsForMinSdk(context_->GetMinSdkVersion(), options_.split_constraints);
+ if (origConstraintSize != options_.split_constraints.size()) {
+ context_->GetDiagnostics()->Warn(DiagMessage()
+ << "requested to split resources prior to min sdk of "
+ << context_->GetMinSdkVersion());
+ }
TableSplitter table_splitter(options_.split_constraints, options_.table_splitter_options);
if (!table_splitter.VerifySplitConstraints(context_)) {
return 1;
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index c6c82b04ff2e..5862d31e3f94 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -73,6 +73,7 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
}
*out_path = parts[0];
+ out_split->name = parts[1];
for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
ConfigDescription config;
if (!ConfigDescription::Parse(config_str, &config)) {
@@ -119,12 +120,15 @@ std::vector<SplitConstraints> AdjustSplitConstraintsForMinSdk(
for (const SplitConstraints& constraints : split_constraints) {
SplitConstraints constraint;
for (const ConfigDescription& config : constraints.configs) {
- if (config.sdkVersion <= min_sdk) {
- constraint.configs.insert(config.CopyWithoutSdkVersion());
- } else {
- constraint.configs.insert(config);
+ const ConfigDescription &configToInsert = (config.sdkVersion <= min_sdk)
+ ? config.CopyWithoutSdkVersion()
+ : config;
+ // only add the config if it actually selects something
+ if (configToInsert != ConfigDescription::DefaultConfig()) {
+ constraint.configs.insert(configToInsert);
}
}
+ constraint.name = constraints.name;
adjusted_constraints.push_back(std::move(constraint));
}
return adjusted_constraints;
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index b9fb5b2868a7..158ef299f6e2 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -22,6 +22,10 @@
#include "test/Test.h"
namespace aapt {
+#define EXPECT_CONFIG_EQ(constraints, config) \
+ EXPECT_EQ(constraints.configs.size(), 1); \
+ EXPECT_EQ(*constraints.configs.begin(), config); \
+ constraints.configs.clear();
TEST(UtilTest, SplitNamesAreSanitized) {
AppInfo app_info{"com.pkg"};
@@ -84,4 +88,287 @@ TEST (UtilTest, LongVersionCodeUndefined) {
EXPECT_EQ(compiled_version_code_major->value.data, 0x61);
}
+
+TEST (UtilTest, ParseSplitParameter) {
+ IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
+ std::string path;
+ SplitConstraints constraints;
+ ConfigDescription expected_configuration;
+
+ // ========== Test IMSI ==========
+ // mcc: 'mcc[0-9]{3}'
+ // mnc: 'mnc[0-9]{1,3}'
+ ASSERT_TRUE(ParseSplitParameter(":mcc310",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setMcc(0x0136)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc004",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setMcc(0x0136)
+ .setMnc(0x0004)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc000",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setMcc(0x0136)
+ .setMnc(0xFFFF)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test LOCALE ==========
+ // locale: '[a-z]{2,3}(-r[a-z]{2})?'
+ // locale: 'b+[a-z]{2,3}(+[a-z[0-9]]{2})?'
+ ASSERT_TRUE(ParseSplitParameter(":es",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setLanguage(0x6573)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":fr-rCA",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setLanguage(0x6672)
+ .setCountry(0x4341)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":b+es+419",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setLanguage(0x6573)
+ .setCountry(0xA424)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test SCREEN_TYPE ==========
+ // orientation: '(port|land|square)'
+ // touchscreen: '(notouch|stylus|finger)'
+ // density" '(anydpi|nodpi|ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|[0-9]*dpi)'
+ ASSERT_TRUE(ParseSplitParameter(":square",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setOrientation(0x03)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":stylus",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setTouchscreen(0x02)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":xxxhdpi",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setDensity(0x0280)
+ .setSdkVersion(0x0004) // version [any density requires donut]
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":land-xhdpi-finger",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setOrientation(0x02)
+ .setTouchscreen(0x03)
+ .setDensity(0x0140)
+ .setSdkVersion(0x0004) // version [any density requires donut]
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test INPUT ==========
+ // keyboard: '(nokeys|qwerty|12key)'
+ // navigation: '(nonav|dpad|trackball|wheel)'
+ // inputFlags: '(keysexposed|keyshidden|keyssoft)'
+ // inputFlags: '(navexposed|navhidden)'
+ ASSERT_TRUE(ParseSplitParameter(":qwerty",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setKeyboard(0x02)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":dpad",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setNavigation(0x02)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":keyssoft-navhidden",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setInputFlags(0x0B)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":keyshidden-nokeys-navexposed-trackball",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setKeyboard(0x01)
+ .setNavigation(0x03)
+ .setInputFlags(0x06)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test SCREEN_SIZE ==========
+ // screenWidth/screenHeight: '[0-9]+x[0-9]+'
+ ASSERT_TRUE(ParseSplitParameter(":1920x1080",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenWidth(0x0780)
+ .setScreenHeight(0x0438)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test VERSION ==========
+ // version 'v[0-9]+'
+
+ // ========== Test SCREEN_CONFIG ==========
+ // screenLayout [direction]: '(ldltr|ldrtl)'
+ // screenLayout [size]: '(small|normal|large|xlarge)'
+ // screenLayout [long]: '(long|notlong)'
+ // uiMode [type]: '(desk|car|television|appliance|watch|vrheadset)'
+ // uiMode [night]: '(night|notnight)'
+ // smallestScreenWidthDp: 'sw[0-9]dp'
+ ASSERT_TRUE(ParseSplitParameter(":ldrtl",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenLayout(0x80)
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":small",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenLayout(0x01)
+ .setSdkVersion(0x0004) // screenLayout (size) requires donut
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":notlong",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenLayout(0x10)
+ .setSdkVersion(0x0004) // screenLayout (long) requires donut
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":ldltr-normal-long",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenLayout(0x62)
+ .setSdkVersion(0x0004) // screenLayout (size|long) requires donut
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":car",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setUiMode(0x03)
+ .setSdkVersion(0x0008) // uiMode requires froyo
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":vrheadset",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setUiMode(0x07)
+ .setSdkVersion(0x001A) // uiMode 'vrheadset' requires oreo
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":television-night",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setUiMode(0x24)
+ .setSdkVersion(0x0008) // uiMode requires froyo
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":sw1920dp",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setSmallestScreenWidthDp(0x0780)
+ .setSdkVersion(0x000D) // smallestScreenWidthDp requires honeycomb mr2
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test SCREEN_SIZE_DP ==========
+ // screenWidthDp: 'w[0-9]dp'
+ // screenHeightDp: 'h[0-9]dp'
+ ASSERT_TRUE(ParseSplitParameter(":w1920dp",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenWidthDp(0x0780)
+ .setSdkVersion(0x000D) // screenWidthDp requires honeycomb mr2
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":h1080dp",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenHeightDp(0x0438)
+ .setSdkVersion(0x000D) // screenHeightDp requires honeycomb mr2
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ // ========== Test SCREEN_CONFIG_2 ==========
+ // screenLayout2: '(round|notround)'
+ // colorMode: '(widecg|nowidecg)'
+ // colorMode: '(highhdr|lowdr)'
+ ASSERT_TRUE(ParseSplitParameter(":round",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setScreenLayout2(0x02)
+ .setSdkVersion(0x0017) // screenLayout2 (round) requires marshmallow
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+ ASSERT_TRUE(ParseSplitParameter(":widecg-highdr",
+ diagnostics, &path, &constraints));
+ expected_configuration = test::ConfigDescriptionBuilder()
+ .setColorMode(0x0A)
+ .setSdkVersion(0x001A) // colorMode (hdr|colour gamut) requires oreo
+ .Build();
+ EXPECT_CONFIG_EQ(constraints, expected_configuration);
+}
+
+TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ IDiagnostics* diagnostics = context.get()->GetDiagnostics();
+ std::vector<SplitConstraints> test_constraints;
+ std::string path;
+
+ test_constraints.push_back({});
+ ASSERT_TRUE(ParseSplitParameter(":v7",
+ diagnostics, &path, &test_constraints.back()));
+ test_constraints.push_back({});
+ ASSERT_TRUE(ParseSplitParameter(":xhdpi",
+ diagnostics, &path, &test_constraints.back()));
+ EXPECT_EQ(test_constraints.size(), 2);
+ EXPECT_EQ(test_constraints[0].name, "v7");
+ EXPECT_EQ(test_constraints[0].configs.size(), 1);
+ EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
+ EXPECT_EQ(test_constraints[1].name, "xhdpi");
+ EXPECT_EQ(test_constraints[1].configs.size(), 1);
+ EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
+
+ auto adjusted_contraints = AdjustSplitConstraintsForMinSdk(26, test_constraints);
+ EXPECT_EQ(adjusted_contraints.size(), 2);
+ EXPECT_EQ(adjusted_contraints[0].name, "v7");
+ EXPECT_EQ(adjusted_contraints[0].configs.size(), 0);
+ EXPECT_EQ(adjusted_contraints[1].name, "xhdpi");
+ EXPECT_EQ(adjusted_contraints[1].configs.size(), 1);
+ EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig());
+}
+
} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
new file mode 100644
index 000000000000..2c356d1491d5
--- /dev/null
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -0,0 +1,2197 @@
+/*
+ * 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 "DumpManifest.h"
+
+#include "LoadedApk.h"
+#include "SdkConstants.h"
+#include "ValueVisitor.h"
+#include "io/File.h"
+#include "io/FileStream.h"
+#include "process/IResourceTableConsumer.h"
+#include "xml/XmlDom.h"
+
+using ::android::base::StringPrintf;
+
+namespace aapt {
+
+/**
+ * These are attribute resource constants for the platform, as found in android.R.attr.
+ */
+enum {
+ LABEL_ATTR = 0x01010001,
+ ICON_ATTR = 0x01010002,
+ NAME_ATTR = 0x01010003,
+ PERMISSION_ATTR = 0x01010006,
+ EXPORTED_ATTR = 0x01010010,
+ GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
+ RESOURCE_ATTR = 0x01010025,
+ DEBUGGABLE_ATTR = 0x0101000f,
+ VALUE_ATTR = 0x01010024,
+ VERSION_CODE_ATTR = 0x0101021b,
+ VERSION_NAME_ATTR = 0x0101021c,
+ SCREEN_ORIENTATION_ATTR = 0x0101001e,
+ MIN_SDK_VERSION_ATTR = 0x0101020c,
+ MAX_SDK_VERSION_ATTR = 0x01010271,
+ REQ_TOUCH_SCREEN_ATTR = 0x01010227,
+ REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
+ REQ_HARD_KEYBOARD_ATTR = 0x01010229,
+ REQ_NAVIGATION_ATTR = 0x0101022a,
+ REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
+ TARGET_SDK_VERSION_ATTR = 0x01010270,
+ TEST_ONLY_ATTR = 0x01010272,
+ ANY_DENSITY_ATTR = 0x0101026c,
+ GL_ES_VERSION_ATTR = 0x01010281,
+ SMALL_SCREEN_ATTR = 0x01010284,
+ NORMAL_SCREEN_ATTR = 0x01010285,
+ LARGE_SCREEN_ATTR = 0x01010286,
+ XLARGE_SCREEN_ATTR = 0x010102bf,
+ REQUIRED_ATTR = 0x0101028e,
+ INSTALL_LOCATION_ATTR = 0x010102b7,
+ SCREEN_SIZE_ATTR = 0x010102ca,
+ SCREEN_DENSITY_ATTR = 0x010102cb,
+ REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
+ COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
+ LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
+ PUBLIC_KEY_ATTR = 0x010103a6,
+ CATEGORY_ATTR = 0x010103e8,
+ BANNER_ATTR = 0x10103f2,
+ ISGAME_ATTR = 0x10103f4,
+ REQUIRED_FEATURE_ATTR = 0x1010557,
+ REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
+ COMPILE_SDK_VERSION_ATTR = 0x01010572,
+ COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
+};
+
+const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
+
+/** Retrieves the attribute of the element with the specified attribute resource id. */
+static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
+ for (auto& a : el->attributes) {
+ if (a.compiled_attribute && a.compiled_attribute.value().id) {
+ if (a.compiled_attribute.value().id.value() == resd_id) {
+ return std::move(&a);
+ }
+ }
+ }
+ return nullptr;
+}
+
+/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
+static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
+ const std::string &name) {
+ return el->FindAttribute(package, name);
+}
+
+class CommonFeatureGroup;
+
+class ManifestExtractor {
+ public:
+ struct Options {
+ /** Include meta information from <meta-data> elements in the output. */
+ bool include_meta_data = false;
+
+ /** Only output permission information. */
+ bool only_permissions = false;
+ };
+
+ explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options)
+ : apk_(apk), options_(options) { }
+
+ class Element {
+ public:
+ Element() = default;
+ virtual ~Element() = default;
+
+ static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
+
+ /** Writes out the extracted contents of the element. */
+ virtual void Print(text::Printer& printer) { }
+
+ /** Adds an element to the list of children of the element. */
+ void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
+
+ /** Retrieves the list of children of the element. */
+ const std::vector<std::unique_ptr<Element>>& children() const {
+ return children_;
+ }
+
+ /** Retrieves the extracted xml element tag. */
+ const std::string tag() const {
+ return tag_;
+ }
+
+ protected:
+ ManifestExtractor* extractor() const {
+ return extractor_;
+ }
+
+ /** Retrieves and stores the information extracted from the xml element. */
+ virtual void Extract(xml::Element* el) { }
+
+ /*
+ * Retrieves a configuration value of the resource entry that best matches the specified
+ * configuration.
+ */
+ static Value* BestConfigValue(ResourceEntry* entry,
+ const ConfigDescription& match) {
+ if (!entry) {
+ return nullptr;
+ }
+
+ // Determine the config that best matches the desired config
+ ResourceConfigValue* best_value = nullptr;
+ for (auto& value : entry->values) {
+ if (!value->config.match(match)) {
+ continue;
+ }
+
+ if (best_value != nullptr) {
+ if (!value->config.isBetterThan(best_value->config, &match)) {
+ if (value->config.compare(best_value->config) != 0) {
+ continue;
+ }
+ }
+ }
+
+ best_value = value.get();
+ }
+
+ // The entry has no values
+ if (!best_value) {
+ return nullptr;
+ }
+
+ return best_value->value.get();
+ }
+
+ /** Retrieves the resource assigned to the specified resource id if one exists. */
+ Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
+ const ConfigDescription& config = DummyConfig()) {
+ if (table) {
+ for (auto& package : table->packages) {
+ if (package->id && package->id.value() == res_id.package_id()) {
+ for (auto& type : package->types) {
+ if (type->id && type->id.value() == res_id.type_id()) {
+ for (auto& entry : type->entries) {
+ if (entry->id && entry->id.value() == res_id.entry_id()) {
+ if (auto value = BestConfigValue(entry.get(), config)) {
+ return value;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ /** Attempts to resolve the reference to a non-reference value. */
+ Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
+ const int kMaxIterations = 40;
+ int i = 0;
+ while (ref && ref->id && i++ < kMaxIterations) {
+ auto table = extractor_->apk_->GetResourceTable();
+ if (auto value = FindValueById(table, ref->id.value(), config)) {
+ if (ValueCast<Reference>(value)) {
+ ref = ValueCast<Reference>(value);
+ } else {
+ return value;
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ /**
+ * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
+ * this will attempt to resolve the reference to an integer value.
+ **/
+ int32_t* GetAttributeInteger(xml::Attribute* attr,
+ const ConfigDescription& config = DummyConfig()) {
+ if (attr != nullptr) {
+ if (attr->compiled_value) {
+ // Resolve references using the dummy configuration
+ Value* value = attr->compiled_value.get();
+ if (ValueCast<Reference>(value)) {
+ value = ResolveReference(ValueCast<Reference>(value), config);
+ } else {
+ value = attr->compiled_value.get();
+ }
+ // Retrieve the integer data if possible
+ if (value != nullptr) {
+ if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
+ return (int32_t*) &intValue->value.data;
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ /**
+ * A version of GetAttributeInteger that returns a default integer if the attribute does not
+ * exist or cannot be resolved to an integer value.
+ **/
+ int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
+ const ConfigDescription& config = DummyConfig()) {
+ auto value = GetAttributeInteger(attr, config);
+ if (value) {
+ return *value;
+ }
+ return def;
+ }
+
+ /**
+ * Retrieves the string value of the attribute. If the value of the attribute is a reference,
+ * this will attempt to resolve the reference to a string value.
+ **/
+ const std::string* GetAttributeString(xml::Attribute* attr,
+ const ConfigDescription& config = DummyConfig()) {
+ if (attr != nullptr) {
+ if (attr->compiled_value) {
+ // Resolve references using the dummy configuration
+ Value* value = attr->compiled_value.get();
+ if (ValueCast<Reference>(value)) {
+ value = ResolveReference(ValueCast<Reference>(value), config);
+ } else {
+ value = attr->compiled_value.get();
+ }
+
+ // Retrieve the string data of the value if possible
+ if (value != nullptr) {
+ if (String* intValue = ValueCast<String>(value)) {
+ return &(*intValue->value);
+ } else if (RawString* rawValue = ValueCast<RawString>(value)) {
+ return &(*rawValue->value);
+ } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
+ return &(*strValue->path);
+ }
+ }
+ }
+ return &attr->value;
+ }
+ return nullptr;
+ }
+
+ /**
+ * A version of GetAttributeString that returns a default string if the attribute does not
+ * exist or cannot be resolved to an string value.
+ **/
+ std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
+ const ConfigDescription& config = DummyConfig()) {
+ auto value = GetAttributeString(attr, config);
+ if (value) {
+ return *value;
+ }
+ return def;
+ }
+
+ private:
+ ManifestExtractor* extractor_;
+ std::vector<std::unique_ptr<Element>> children_;
+ std::string tag_;
+ };
+
+ friend Element;
+
+ /** Creates a default configuration used to retrieve resources. */
+ static ConfigDescription DummyConfig() {
+ ConfigDescription config;
+ config.orientation = android::ResTable_config::ORIENTATION_PORT;
+ config.density = android::ResTable_config::DENSITY_MEDIUM;
+ config.sdkVersion = 10000; // Very high.
+ config.screenWidthDp = 320;
+ config.screenHeightDp = 480;
+ config.smallestScreenWidthDp = 320;
+ config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
+ return config;
+ }
+
+ bool Dump(text::Printer& printer, IDiagnostics* diag);
+
+ /** Recursively visit the xml element tree and return a processed badging element tree. */
+ std::unique_ptr<Element> Visit(xml::Element* element);
+
+ /** Raises the target sdk value if the min target is greater than the current target. */
+ void RaiseTargetSdk(int32_t min_target) {
+ if (min_target > target_sdk_) {
+ target_sdk_ = min_target;
+ }
+ }
+
+ /**
+ * Retrieves the default feature group that features are added into when <uses-feature>
+ * are not in a <feature-group> element.
+ **/
+ CommonFeatureGroup* GetCommonFeatureGroup() {
+ return commonFeatureGroup_.get();
+ }
+
+ /**
+ * Retrieves a mapping of density values to Configurations for retrieving resources that would be
+ * used for that density setting.
+ **/
+ const std::map<uint16_t, ConfigDescription> densities() const {
+ return densities_;
+ }
+
+ /**
+ * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
+ * would be used for that locale setting.
+ **/
+ const std::map<std::string, ConfigDescription> locales() const {
+ return locales_;
+ }
+
+ /** Retrieves the current stack of parent during data extraction. */
+ const std::vector<Element*> parent_stack() const {
+ return parent_stack_;
+ }
+
+ int32_t target_sdk() const {
+ return target_sdk_;
+ }
+
+ LoadedApk* const apk_;
+ const Options options_;
+
+ private:
+ std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
+ std::map<std::string, ConfigDescription> locales_;
+ std::map<uint16_t, ConfigDescription> densities_;
+ std::vector<Element*> parent_stack_;
+ int32_t target_sdk_ = 0;
+};
+
+template<typename T> T* ElementCast(ManifestExtractor::Element* element);
+
+/** Recurs through the children of the specified root in depth-first order. */
+static void ForEachChild(ManifestExtractor::Element* root,
+ std::function<void(ManifestExtractor::Element*)> f) {
+ for (auto& child : root->children()) {
+ f(child.get());
+ ForEachChild(child.get(), f);
+ }
+}
+
+/**
+ * Checks the element and its recursive children for an element that makes the specified
+ * conditional function return true. Returns the first element that makes the conditional function
+ * return true.
+ **/
+static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
+ std::function<bool(ManifestExtractor::Element*)> f) {
+ if (f(root)) {
+ return root;
+ }
+ for (auto& child : root->children()) {
+ if (auto b2 = FindElement(child.get(), f)) {
+ return b2;
+ }
+ }
+ return nullptr;
+}
+
+/** Represents the <manifest> elements **/
+class Manifest : public ManifestExtractor::Element {
+ public:
+ Manifest() = default;
+ std::string package;
+ int32_t versionCode;
+ std::string versionName;
+ const std::string* split = nullptr;
+ const std::string* platformVersionName = nullptr;
+ const std::string* platformVersionCode = nullptr;
+ const int32_t* compilesdkVersion = nullptr;
+ const std::string* compilesdkVersionCodename = nullptr;
+ const int32_t* installLocation = nullptr;
+
+ void Extract(xml::Element* manifest) override {
+ package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
+ versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
+ versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
+ split = GetAttributeString(FindAttribute(manifest, {}, "split"));
+
+ // Extract the platform build info
+ platformVersionName = GetAttributeString(FindAttribute(manifest, {},
+ "platformBuildVersionName"));
+ platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
+ "platformBuildVersionCode"));
+
+ // Extract the compile sdk info
+ compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
+ compilesdkVersionCodename = GetAttributeString(
+ FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
+ installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ printer.Print(StringPrintf("package: name='%s' ", package.data()));
+ printer.Print(StringPrintf("versionCode='%s' ",
+ (versionCode > 0) ? std::to_string(versionCode).data() : ""));
+ printer.Print(StringPrintf("versionName='%s'", versionName.data()));
+
+ if (split) {
+ printer.Print(StringPrintf(" split='%s'", split->data()));
+ }
+ if (platformVersionName) {
+ printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
+ }
+ if (platformVersionCode) {
+ printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
+ }
+ if (compilesdkVersion) {
+ printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
+ }
+ if (compilesdkVersionCodename) {
+ printer.Print(StringPrintf(" compileSdkVersionCodename='%s'",
+ compilesdkVersionCodename->data()));
+ }
+ printer.Print("\n");
+
+ if (installLocation) {
+ switch (*installLocation) {
+ case 0:
+ printer.Print("install-location:'auto'\n");
+ break;
+ case 1:
+ printer.Print("install-location:'internalOnly'\n");
+ break;
+ case 2:
+ printer.Print("install-location:'preferExternal'\n");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+};
+
+/** Represents <application> elements. **/
+class Application : public ManifestExtractor::Element {
+ public:
+ Application() = default;
+ std::string label;
+ std::string icon;
+ std::string banner;
+ int32_t is_game;
+ int32_t debuggable;
+ int32_t test_only;
+ bool has_multi_arch;
+
+ /** Mapping from locales to app names. */
+ std::map<std::string, std::string> locale_labels;
+
+ /** Mapping from densities to app icons. */
+ std::map<uint16_t, std::string> density_icons;
+
+ void Extract(xml::Element* element) override {
+ label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+ icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
+ test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
+ banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
+ is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
+ debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
+
+ // We must search by name because the multiArch flag hasn't been API
+ // frozen yet.
+ has_multi_arch = (GetAttributeIntegerDefault(
+ FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
+
+ // Retrieve the app names for every locale the app supports
+ auto attr = FindAttribute(element, LABEL_ATTR);
+ for (auto& config : extractor()->locales()) {
+ if (auto label = GetAttributeString(attr, config.second)) {
+ if (label) {
+ locale_labels.insert(std::make_pair(config.first, *label));
+ }
+ }
+ }
+
+ // Retrieve the icons for the densities the app supports
+ attr = FindAttribute(element, ICON_ATTR);
+ for (auto& config : extractor()->densities()) {
+ if (auto resource = GetAttributeString(attr, config.second)) {
+ if (resource) {
+ density_icons.insert(std::make_pair(config.first, *resource));
+ }
+ }
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ // Print the labels for every locale
+ for (auto p : locale_labels) {
+ if (p.first.empty()) {
+ printer.Print(StringPrintf("application-label:'%s'\n",
+ android::ResTable::normalizeForOutput(p.second.data())
+ .c_str()));
+ } else {
+ printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
+ android::ResTable::normalizeForOutput(p.second.data())
+ .c_str()));
+ }
+ }
+
+ // Print the icon paths for every density
+ for (auto p : density_icons) {
+ printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
+ }
+
+ // Print the application info
+ printer.Print(StringPrintf("application: label='%s' ",
+ android::ResTable::normalizeForOutput(label.data()).c_str()));
+ printer.Print(StringPrintf("icon='%s'", icon.data()));
+ if (!banner.empty()) {
+ printer.Print(StringPrintf(" banner='%s'", banner.data()));
+ }
+ printer.Print("\n");
+
+ if (test_only != 0) {
+ printer.Print(StringPrintf("testOnly='%d'\n", test_only));
+ }
+ if (is_game != 0) {
+ printer.Print("application-isGame\n");
+ }
+ if (debuggable != 0) {
+ printer.Print("application-debuggable\n");
+ }
+ }
+};
+
+/** Represents <uses-sdk> elements. **/
+class UsesSdkBadging : public ManifestExtractor::Element {
+ public:
+ UsesSdkBadging() = default;
+ const int32_t* min_sdk = nullptr;
+ const std::string* min_sdk_name = nullptr;
+ const int32_t* max_sdk = nullptr;
+ const int32_t* target_sdk = nullptr;
+ const std::string* target_sdk_name = nullptr;
+
+ void Extract(xml::Element* element) override {
+ min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
+ min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
+ max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
+ target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
+ target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
+
+ // Detect the target sdk of the element
+ if ((min_sdk_name && *min_sdk_name == "Donut")
+ || (target_sdk_name && *target_sdk_name == "Donut")) {
+ extractor()->RaiseTargetSdk(4);
+ }
+ if (min_sdk) {
+ extractor()->RaiseTargetSdk(*min_sdk);
+ }
+ if (target_sdk) {
+ extractor()->RaiseTargetSdk(*target_sdk);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ if (min_sdk) {
+ printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
+ } else if (min_sdk_name) {
+ printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
+ }
+ if (max_sdk) {
+ printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
+ }
+ if (target_sdk) {
+ printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
+ } else if (target_sdk_name) {
+ printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
+ }
+ }
+};
+
+/** Represents <uses-configuration> elements. **/
+class UsesConfiguarion : public ManifestExtractor::Element {
+ public:
+ UsesConfiguarion() = default;
+ int32_t req_touch_screen = 0;
+ int32_t req_keyboard_type = 0;
+ int32_t req_hard_keyboard = 0;
+ int32_t req_navigation = 0;
+ int32_t req_five_way_nav = 0;
+
+ void Extract(xml::Element* element) override {
+ req_touch_screen = GetAttributeIntegerDefault(
+ FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
+ req_keyboard_type = GetAttributeIntegerDefault(
+ FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
+ req_hard_keyboard = GetAttributeIntegerDefault(
+ FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
+ req_navigation = GetAttributeIntegerDefault(
+ FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
+ req_five_way_nav = GetAttributeIntegerDefault(
+ FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
+ }
+
+ void Print(text::Printer& printer) override {
+ printer.Print("uses-configuration:");
+ if (req_touch_screen != 0) {
+ printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
+ }
+ if (req_keyboard_type != 0) {
+ printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
+ }
+ if (req_hard_keyboard != 0) {
+ printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
+ }
+ if (req_navigation != 0) {
+ printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation));
+ }
+ if (req_five_way_nav != 0) {
+ printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
+ }
+ printer.Print("\n");
+ }
+};
+
+/** Represents <supports-screen> elements. **/
+class SupportsScreen : public ManifestExtractor::Element {
+ public:
+ SupportsScreen() = default;
+ int32_t small_screen = 1;
+ int32_t normal_screen = 1;
+ int32_t large_screen = 1;
+ int32_t xlarge_screen = 1;
+ int32_t any_density = 1;
+ int32_t requires_smallest_width_dp = 0;
+ int32_t compatible_width_limit_dp = 0;
+ int32_t largest_width_limit_dp = 0;
+
+ void Extract(xml::Element* element) override {
+ small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
+ normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
+ large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
+ xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
+ any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
+
+ requires_smallest_width_dp = GetAttributeIntegerDefault(
+ FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
+ compatible_width_limit_dp = GetAttributeIntegerDefault(
+ FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
+ largest_width_limit_dp = GetAttributeIntegerDefault(
+ FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
+
+ // For modern apps, if screen size buckets haven't been specified
+ // but the new width ranges have, then infer the buckets from them.
+ if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
+ && requires_smallest_width_dp > 0) {
+ int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
+ : requires_smallest_width_dp;
+ small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
+ normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
+ large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
+ xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
+ }
+ }
+
+ void PrintScreens(text::Printer& printer, int32_t target_sdk) {
+ int32_t small_screen_temp = small_screen;
+ int32_t normal_screen_temp = normal_screen;
+ int32_t large_screen_temp = large_screen;
+ int32_t xlarge_screen_temp = xlarge_screen;
+ int32_t any_density_temp = any_density;
+
+ // Determine default values for any unspecified screen sizes,
+ // based on the target SDK of the package. As of 4 (donut)
+ // the screen size support was introduced, so all default to
+ // enabled.
+ if (small_screen_temp > 0) {
+ small_screen_temp = target_sdk >= 4 ? -1 : 0;
+ }
+ if (normal_screen_temp > 0) {
+ normal_screen_temp = -1;
+ }
+ if (large_screen_temp > 0) {
+ large_screen_temp = target_sdk >= 4 ? -1 : 0;
+ }
+ if (xlarge_screen_temp > 0) {
+ // Introduced in Gingerbread.
+ xlarge_screen_temp = target_sdk >= 9 ? -1 : 0;
+ }
+ if (any_density_temp > 0) {
+ any_density_temp = (target_sdk >= 4 || requires_smallest_width_dp > 0
+ || compatible_width_limit_dp > 0) ? -1 : 0;
+ }
+
+ // Print the formatted screen info
+ printer.Print("supports-screens:");
+ if (small_screen_temp != 0) {
+ printer.Print(" 'small'");
+ }
+ if (normal_screen_temp != 0) {
+ printer.Print(" 'normal'");
+ }
+ if (large_screen_temp != 0) {
+ printer.Print(" 'large'");
+ }
+ if (xlarge_screen_temp != 0) {
+ printer.Print(" 'xlarge'");
+ }
+ printer.Print("\n");
+ printer.Print(StringPrintf("supports-any-density: '%s'\n",
+ (any_density_temp ) ? "true" : "false"));
+ if (requires_smallest_width_dp > 0) {
+ printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
+ }
+ if (compatible_width_limit_dp > 0) {
+ printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
+ }
+ if (largest_width_limit_dp > 0) {
+ printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
+ }
+ }
+};
+
+/** Represents <feature-group> elements. **/
+class FeatureGroup : public ManifestExtractor::Element {
+ public:
+ FeatureGroup() = default;
+ std::string label;
+ int32_t open_gles_version = 0;
+
+ void Extract(xml::Element* element) override {
+ label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+ }
+
+ virtual void PrintGroup(text::Printer& printer) {
+ printer.Print(StringPrintf("feature-group: label='%s'\n", label.data()));
+ if (open_gles_version > 0) {
+ printer.Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
+ }
+
+ for (auto feature : features_) {
+ printer.Print(StringPrintf(" uses-feature%s: name='%s'",
+ (feature.second.required ? "" : "-not-required"),
+ feature.first.data()));
+ if (feature.second.version > 0) {
+ printer.Print(StringPrintf(" version='%d'", feature.second.version));
+ }
+ printer.Print("\n");
+ }
+ }
+
+ /** Adds a feature to the feature group. */
+ void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
+ features_.insert(std::make_pair(name, Feature{ required, version }));
+ if (required) {
+ if (name == "android.hardware.camera.autofocus" ||
+ name == "android.hardware.camera.flash") {
+ AddFeature("android.hardware.camera", true);
+ } else if (name == "android.hardware.location.gps" ||
+ name == "android.hardware.location.network") {
+ AddFeature("android.hardware.location", true);
+ } else if (name == "android.hardware.faketouch.multitouch") {
+ AddFeature("android.hardware.faketouch", true);
+ } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
+ name == "android.hardware.faketouch.multitouch.jazzhands") {
+ AddFeature("android.hardware.faketouch.multitouch", true);
+ AddFeature("android.hardware.faketouch", true);
+ } else if (name == "android.hardware.touchscreen.multitouch") {
+ AddFeature("android.hardware.touchscreen", true);
+ } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
+ name == "android.hardware.touchscreen.multitouch.jazzhands") {
+ AddFeature("android.hardware.touchscreen.multitouch", true);
+ AddFeature("android.hardware.touchscreen", true);
+ } else if (name == "android.hardware.opengles.aep") {
+ const int kOpenGLESVersion31 = 0x00030001;
+ if (kOpenGLESVersion31 > open_gles_version) {
+ open_gles_version = kOpenGLESVersion31;
+ }
+ }
+ }
+ }
+
+ /** Returns true if the feature group has the given feature. */
+ virtual bool HasFeature(const std::string& name) {
+ return features_.find(name) != features_.end();
+ }
+
+ /** Merges the features of another feature group into this group. */
+ void Merge(FeatureGroup* group) {
+ open_gles_version = std::max(open_gles_version, group->open_gles_version);
+ for (auto& feature : group->features_) {
+ features_.insert(feature);
+ }
+ }
+
+ protected:
+ struct Feature {
+ public:
+ bool required = false;
+ int32_t version = -1;
+ };
+
+ /* Mapping of feature names to their properties. */
+ std::map<std::string, Feature> features_;
+};
+
+/**
+ * Represents the default feature group for the application if no <feature-group> elements are
+ * present in the manifest.
+ **/
+class CommonFeatureGroup : public FeatureGroup {
+ public:
+ CommonFeatureGroup() = default;
+ void PrintGroup(text::Printer& printer) override {
+ FeatureGroup::PrintGroup(printer);
+
+ // Also print the implied features
+ for (auto feature : implied_features_) {
+ if (features_.find(feature.first) == features_.end()) {
+ const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
+ printer.Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
+ printer.Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
+ feature.first.data()));
+
+ // Print the reasons as a sentence
+ size_t count = 0;
+ for (auto reason : feature.second.reasons) {
+ printer.Print(reason);
+ if (count + 2 < feature.second.reasons.size()) {
+ printer.Print(", ");
+ } else if (count + 1 < feature.second.reasons.size()) {
+ printer.Print(", and ");
+ }
+ count++;
+ }
+ printer.Print("'\n");
+ }
+ }
+ }
+
+ /** Returns true if the feature group has the given feature. */
+ bool HasFeature(const std::string& name) override {
+ return FeatureGroup::HasFeature(name)
+ || implied_features_.find(name) != implied_features_.end();
+ }
+
+ /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
+ void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
+ auto entry = implied_features_.find(name);
+ if (entry == implied_features_.end()) {
+ implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
+ entry = implied_features_.find(name);
+ }
+
+ // A non-sdk 23 implied feature takes precedence.
+ if (entry->second.implied_from_sdk_k23 && !sdk23) {
+ entry->second.implied_from_sdk_k23 = false;
+ }
+
+ entry->second.reasons.insert(reason);
+ }
+
+ /**
+ * Adds a feature to a set of implied features for all features that are implied by the presence
+ * of the permission.
+ **/
+ void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
+ if (name == "android.permission.CAMERA") {
+ addImpliedFeature("android.hardware.camera",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
+ if (targetSdk < SDK_LOLLIPOP) {
+ addImpliedFeature("android.hardware.location.gps",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+ addImpliedFeature("android.hardware.location.gps",
+ StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
+ sdk23);
+ }
+ addImpliedFeature("android.hardware.location",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+ if (targetSdk < SDK_LOLLIPOP) {
+ addImpliedFeature("android.hardware.location.network",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+ addImpliedFeature("android.hardware.location.network",
+ StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
+ sdk23);
+ }
+ addImpliedFeature("android.hardware.location",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
+ name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+ name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+ addImpliedFeature("android.hardware.location",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.BLUETOOTH" ||
+ name == "android.permission.BLUETOOTH_ADMIN") {
+ if (targetSdk > SDK_DONUT) {
+ addImpliedFeature("android.hardware.bluetooth",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+ addImpliedFeature("android.hardware.bluetooth",
+ StringPrintf("targetSdkVersion > %d", SDK_DONUT),
+ sdk23);
+ }
+
+ } else if (name == "android.permission.RECORD_AUDIO") {
+ addImpliedFeature("android.hardware.microphone",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+ name == "android.permission.CHANGE_WIFI_STATE" ||
+ name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+ addImpliedFeature("android.hardware.wifi",
+ StringPrintf("requested %s permission", name.data()),
+ sdk23);
+
+ } else if (name == "android.permission.CALL_PHONE" ||
+ name == "android.permission.CALL_PRIVILEGED" ||
+ name == "android.permission.MODIFY_PHONE_STATE" ||
+ name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+ name == "android.permission.READ_SMS" ||
+ name == "android.permission.RECEIVE_SMS" ||
+ name == "android.permission.RECEIVE_MMS" ||
+ name == "android.permission.RECEIVE_WAP_PUSH" ||
+ name == "android.permission.SEND_SMS" ||
+ name == "android.permission.WRITE_APN_SETTINGS" ||
+ name == "android.permission.WRITE_SMS") {
+ addImpliedFeature("android.hardware.telephony",
+ "requested a telephony permission",
+ sdk23);
+ }
+ }
+
+ private:
+ /**
+ * Represents a feature that has been automatically added due to a pre-requisite or for some
+ * other reason.
+ */
+ struct ImpliedFeature {
+ explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
+
+ /** List of human-readable reasons for why this feature was implied. */
+ std::set<std::string> reasons;
+
+ // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
+ bool implied_from_sdk_k23;
+ };
+
+ /* Mapping of implied feature names to their properties. */
+ std::map<std::string, ImpliedFeature> implied_features_;
+};
+
+/** Represents <uses-feature> elements. **/
+class UsesFeature : public ManifestExtractor::Element {
+ public:
+ UsesFeature() = default;
+ void Extract(xml::Element* element) override {
+ const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
+ bool required = GetAttributeIntegerDefault(
+ FindAttribute(element, REQUIRED_ATTR), true) != 0;
+ int32_t version = GetAttributeIntegerDefault(
+ FindAttribute(element, kAndroidNamespace, "version"), 0);
+
+ // Add the feature to the parent feature group element if one exists; otherwise, add it to the
+ // common feature group
+ FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
+ if (!feature_group) {
+ feature_group = extractor()->GetCommonFeatureGroup();
+ } else {
+ // All features in side of <feature-group> elements are required.
+ required = true;
+ }
+
+ if (name) {
+ feature_group->AddFeature(*name, required, version);
+ } else if (gl) {
+ feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
+ }
+ }
+};
+
+/** Represents <uses-permission> elements. **/
+class UsesPermission : public ManifestExtractor::Element {
+ public:
+ UsesPermission() = default;
+ std::string name;
+ std::string requiredFeature;
+ std::string requiredNotFeature;
+ int32_t required = true;
+ int32_t maxSdkVersion = -1;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ requiredFeature = GetAttributeStringDefault(
+ FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
+ requiredNotFeature = GetAttributeStringDefault(
+ FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
+ maxSdkVersion = GetAttributeIntegerDefault(
+ FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
+
+ if (!name.empty()) {
+ CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ if (!name.empty()) {
+ printer.Print(StringPrintf("uses-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ if (!requiredFeature.empty()) {
+ printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
+ }
+ if (!requiredNotFeature.empty()) {
+ printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
+ }
+ printer.Print("\n");
+ if (required == 0) {
+ printer.Print(StringPrintf("optional-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ printer.Print("\n");
+ }
+ }
+ }
+
+ void PrintImplied(text::Printer& printer, const std::string& reason) {
+ printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ printer.Print(StringPrintf(" reason='%s'\n", reason.data()));
+ }
+};
+
+/** Represents <uses-permission-sdk-23> elements. **/
+class UsesPermissionSdk23 : public ManifestExtractor::Element {
+ public:
+ UsesPermissionSdk23() = default;
+ const std::string* name = nullptr;
+ const int32_t* maxSdkVersion = nullptr;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
+
+ if (name) {
+ CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ if (name) {
+ printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
+ if (maxSdkVersion) {
+ printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
+ }
+ printer.Print("\n");
+ }
+ }
+};
+
+/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
+class Permission : public ManifestExtractor::Element {
+ public:
+ Permission() = default;
+ std::string name;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ }
+
+ void Print(text::Printer& printer) override {
+ if (extractor()->options_.only_permissions && !name.empty()) {
+ printer.Print(StringPrintf("permission: %s\n", name.data()));
+ }
+ }
+};
+
+/** Represents <activity> elements. **/
+class Activity : public ManifestExtractor::Element {
+ public:
+ Activity() = default;
+ std::string name;
+ std::string icon;
+ std::string label;
+ std::string banner;
+
+ bool has_component_ = false;
+ bool has_launcher_category = false;
+ bool has_leanback_launcher_category = false;
+ bool has_main_action = false;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+ icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
+ banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
+
+ // Retrieve the package name from the manifest
+ std::string package;
+ for (auto& parent : extractor()->parent_stack()) {
+ if (auto manifest = ElementCast<Manifest>(parent)) {
+ package = manifest->package;
+ break;
+ }
+ }
+
+ // Fully qualify the activity name
+ ssize_t idx = name.find(".");
+ if (idx == 0) {
+ name = package + name;
+ } else if (idx < 0) {
+ name = package + "." + name;
+ }
+
+ auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
+ if (orientation) {
+ CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ int orien = *orientation;
+ if (orien == 0 || orien == 6 || orien == 8) {
+ // Requests landscape, sensorLandscape, or reverseLandscape.
+ common->addImpliedFeature("android.hardware.screen.landscape",
+ "one or more activities have specified a landscape orientation",
+ false);
+ } else if (orien == 1 || orien == 7 || orien == 9) {
+ // Requests portrait, sensorPortrait, or reversePortrait.
+ common->addImpliedFeature("android.hardware.screen.portrait",
+ "one or more activities have specified a portrait orientation",
+ false);
+ }
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ // Print whether the activity has the HOME category and a the MAIN action
+ if (has_main_action && has_launcher_category) {
+ printer.Print("launchable-activity:");
+ if (!name.empty()) {
+ printer.Print(StringPrintf(" name='%s' ", name.data()));
+ }
+ printer.Print(StringPrintf(" label='%s' icon='%s'\n",
+ android::ResTable::normalizeForOutput(label.data()).c_str(),
+ icon.data()));
+ }
+
+ // Print wether the activity has the HOME category and a the MAIN action
+ if (has_leanback_launcher_category) {
+ printer.Print("leanback-launchable-activity:");
+ if (!name.empty()) {
+ printer.Print(StringPrintf(" name='%s' ", name.data()));
+ }
+ printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
+ android::ResTable::normalizeForOutput(label.data()).c_str(),
+ icon.data(), banner.data()));
+ }
+ }
+};
+
+/** Represents <intent-filter> elements. */
+class IntentFilter : public ManifestExtractor::Element {
+ public:
+ IntentFilter() = default;
+};
+
+/** Represents <category> elements. */
+class Category : public ManifestExtractor::Element {
+ public:
+ Category() = default;
+ std::string component = "";
+
+ void Extract(xml::Element* element) override {
+ const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
+
+ auto parent_stack = extractor()->parent_stack();
+ if (category && ElementCast<IntentFilter>(parent_stack[0])
+ && ElementCast<Activity>(parent_stack[1])) {
+ Activity* activity = ElementCast<Activity>(parent_stack[1]);
+
+ if (*category == "android.intent.category.LAUNCHER") {
+ activity->has_launcher_category = true;
+ } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
+ activity->has_leanback_launcher_category = true;
+ } else if (*category == "android.intent.category.HOME") {
+ component = "launcher";
+ }
+ }
+ }
+};
+
+/**
+ * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
+ * elements nested within.
+ **/
+class Provider : public ManifestExtractor::Element {
+ public:
+ Provider() = default;
+ bool has_required_saf_attributes = false;
+
+ void Extract(xml::Element* element) override {
+ const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
+ const int32_t* grant_uri_permissions = GetAttributeInteger(
+ FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
+ const std::string* permission = GetAttributeString(
+ FindAttribute(element, PERMISSION_ATTR));
+
+ has_required_saf_attributes = ((exported && *exported != 0)
+ && (grant_uri_permissions && *grant_uri_permissions != 0)
+ && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
+ }
+};
+
+/** Represents <receiver> elements. **/
+class Receiver : public ManifestExtractor::Element {
+ public:
+ Receiver() = default;
+ const std::string* permission = nullptr;
+ bool has_component = false;
+
+ void Extract(xml::Element* element) override {
+ permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
+ }
+};
+
+/**Represents <service> elements. **/
+class Service : public ManifestExtractor::Element {
+ public:
+ Service() = default;
+ const std::string* permission = nullptr;
+ bool has_component = false;
+
+ void Extract(xml::Element* element) override {
+ permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
+ }
+};
+
+/** Represents <uses-library> elements. **/
+class UsesLibrary : public ManifestExtractor::Element {
+ public:
+ UsesLibrary() = default;
+ std::string name;
+ int required;
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ if (!name.empty()) {
+ printer.Print(StringPrintf("uses-library%s:'%s'\n",
+ (required == 0) ? "-not-required" : "", name.data()));
+ }
+ }
+};
+
+/**
+ * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
+ * explicitly enable meta data printing.
+ **/
+class MetaData : public ManifestExtractor::Element {
+ public:
+ MetaData() = default;
+ std::string name;
+ const std::string* value;
+ const int* value_int;
+ const std::string* resource;
+ const int* resource_int;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ value = GetAttributeString(FindAttribute(element, VALUE_ATTR));
+ value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
+ resource = GetAttributeString(FindAttribute(element, RESOURCE_ATTR));
+ resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ if (extractor()->options_.include_meta_data && !name.empty()) {
+ printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
+ if (value) {
+ printer.Print(StringPrintf("value='%s' ", value->data()));
+ } else if (value_int) {
+ printer.Print(StringPrintf("value='%d' ", *value_int));
+ } else {
+ if (resource) {
+ printer.Print(StringPrintf("resource='%s' ", resource->data()));
+ } else if (resource_int) {
+ printer.Print(StringPrintf("resource='%d' ", *resource_int));
+ }
+ }
+ printer.Print("\n");
+ }
+ }
+};
+
+/**
+ * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
+ * service components.
+ **/
+class Action : public ManifestExtractor::Element {
+ public:
+ Action() = default;
+ std::string component = "";
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+
+ if (ElementCast<IntentFilter>(parent_stack[0])) {
+ if (ElementCast<Activity>(parent_stack[1])) {
+ // Detects the presence of a particular type of activity.
+ Activity* activity = ElementCast<Activity>(parent_stack[1]);
+ auto map = std::map<std::string, std::string>({
+ { "android.intent.action.MAIN" , "main" },
+ { "android.intent.action.VIDEO_CAMERA" , "camera" },
+ { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
+ });
+
+ auto entry = map.find(action);
+ if (entry != map.end()) {
+ component = entry->second;
+ activity->has_component_ = true;
+ }
+
+ if (action == "android.intent.action.MAIN") {
+ activity->has_main_action = true;
+ }
+
+ } else if (ElementCast<Receiver>(parent_stack[1])) {
+ // Detects the presence of a particular type of receiver. If the action requires a
+ // permission, then the receiver element is checked for the permission.
+ Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
+ auto map = std::map<std::string, std::string>({
+ { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
+ { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
+ });
+
+ auto permissions = std::map<std::string, std::string>({
+ { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
+ });
+
+ auto entry = map.find(action);
+ auto permission = permissions.find(action);
+ if (entry != map.end() && (permission == permissions.end()
+ || (receiver->permission && permission->second == *receiver->permission))) {
+ receiver->has_component = true;
+ component = entry->second;
+ }
+
+ } else if (ElementCast<Service>(parent_stack[1])) {
+ // Detects the presence of a particular type of service. If the action requires a
+ // permission, then the service element is checked for the permission.
+ Service* service = ElementCast<Service>(parent_stack[1]);
+ auto map = std::map<std::string, std::string>({
+ { "android.view.InputMethod" , "ime" },
+ { "android.service.wallpaper.WallpaperService" , "wallpaper" },
+ { "android.accessibilityservice.AccessibilityService" , "accessibility" },
+ { "android.printservice.PrintService" , "print-service" },
+ { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
+ { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
+ { "android.service.notification.NotificationListenerService" ,"notification-listener" },
+ { "android.service.dreams.DreamService" , "dream" },
+ });
+
+ auto permissions = std::map<std::string, std::string>({
+ { "android.accessibilityservice.AccessibilityService" ,
+ "android.permission.BIND_ACCESSIBILITY_SERVICE" },
+ { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
+ { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
+ "android.permission.BIND_NFC_SERVICE" },
+ { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
+ "android.permission.BIND_NFC_SERVICE" },
+ { "android.service.notification.NotificationListenerService" ,
+ "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
+ { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
+ });
+
+ auto entry = map.find(action);
+ auto permission = permissions.find(action);
+ if (entry != map.end() && (permission == permissions.end()
+ || (service->permission && permission->second == *service->permission))) {
+ service->has_component= true;
+ component = entry->second;
+ }
+
+ } else if (ElementCast<Provider>(parent_stack[1])) {
+ // Detects the presence of a particular type of receiver. If the provider requires a
+ // permission, then the provider element is checked for the permission.
+ // Detect whether this action
+ Provider* provider = ElementCast<Provider>(parent_stack[1]);
+ if (action == "android.content.action.DOCUMENTS_PROVIDER"
+ && provider->has_required_saf_attributes) {
+ component = "document-provider";
+ }
+ }
+ }
+
+ // Represents a searchable interface
+ if (action == "android.intent.action.SEARCH") {
+ component = "search";
+ }
+ }
+};
+
+/**
+ * Represents <supports-input> elements. The element may have <input-type> elements nested within.
+ **/
+class SupportsInput : public ManifestExtractor::Element {
+ public:
+ SupportsInput() = default;
+ std::vector<std::string> inputs;
+
+ void Print(text::Printer& printer) override {
+ const size_t size = inputs.size();
+ if (size > 0) {
+ printer.Print("supports-input: '");
+ for (size_t i = 0; i < size; i++) {
+ printer.Print(StringPrintf("value='%s' ", inputs[i].data()));
+ }
+ printer.Print("\n");
+ }
+ }
+};
+
+/** Represents <input-type> elements. **/
+class InputType : public ManifestExtractor::Element {
+ public:
+ InputType() = default;
+ void Extract(xml::Element* element) override {
+ auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ auto parent_stack = extractor()->parent_stack();
+
+ // Add the input to the set of supported inputs
+ if (name && ElementCast<SupportsInput>(parent_stack[0])) {
+ SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
+ supports->inputs.push_back(*name);
+ }
+ }
+};
+
+/** Represents <original-package> elements. **/
+class OriginalPackage : public ManifestExtractor::Element {
+ public:
+ OriginalPackage() = default;
+ const std::string* name = nullptr;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ if (name) {
+ printer.Print(StringPrintf("original-package:'%s'\n", name->data()));
+ }
+ }
+};
+
+/** * Represents <package-verifier> elements. **/
+class PackageVerifier : public ManifestExtractor::Element {
+ public:
+ PackageVerifier() = default;
+ const std::string* name = nullptr;
+ const std::string* public_key = nullptr;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ if (name && public_key) {
+ printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
+ name->data(), public_key->data()));
+ }
+ }
+};
+
+/** Represents <uses-package> elements. **/
+class UsesPackage : public ManifestExtractor::Element {
+ public:
+ UsesPackage() = default;
+ const std::string* name = nullptr;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ if (name) {
+ printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+ }
+ }
+};
+
+/** Represents <screen> elements found in <compatible-screens> elements. */
+class Screen : public ManifestExtractor::Element {
+ public:
+ Screen() = default;
+ const int32_t* size = nullptr;
+ const int32_t* density = nullptr;
+
+ void Extract(xml::Element* element) override {
+ size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
+ density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
+ }
+};
+
+/**
+ * Represents <compatible-screens> elements. These elements have <screen> elements nested within
+ * that each denote a supported screen size and screen density.
+ **/
+class CompatibleScreens : public ManifestExtractor::Element {
+ public:
+ CompatibleScreens() = default;
+ void Print(text::Printer& printer) override {
+ printer.Print("compatible-screens:");
+
+ bool first = true;
+ ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
+ if (auto screen = ElementCast<Screen>(el)) {
+ if (first) {
+ first = false;
+ } else {
+ printer.Print(",");
+ }
+
+ if (screen->size && screen->density) {
+ printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
+ }
+ }
+ });
+ printer.Print("\n");
+ }
+};
+
+/** Represents <supports-gl-texture> elements. **/
+class SupportsGlTexture : public ManifestExtractor::Element {
+ public:
+ SupportsGlTexture() = default;
+ const std::string* name = nullptr;
+
+ void Extract(xml::Element* element) override {
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ }
+
+ void Print(text::Printer& printer) override {
+ if (name) {
+ printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
+ }
+ }
+};
+
+/** Recursively prints the extracted badging element. */
+static void Print(ManifestExtractor::Element* el, text::Printer& printer) {
+ el->Print(printer);
+ for (auto &child : el->children()) {
+ Print(child.get(), printer);
+ }
+}
+
+bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
+ // Load the manifest
+ std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
+ if (doc == nullptr) {
+ diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
+ return false;
+ }
+
+ xml::Element* element = doc->root.get();
+ if (element->name != "manifest") {
+ diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
+ return false;
+ }
+
+ // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
+ // printing only permission elements is requested
+ if (options_.only_permissions) {
+ std::unique_ptr<ManifestExtractor::Element> manifest_element =
+ ManifestExtractor::Element::Inflate(this, element);
+
+ if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
+ for (xml::Element* child : element->GetChildElements()) {
+ if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
+ || child->name == "permission") {
+ auto permission_element = ManifestExtractor::Element::Inflate(this, child);
+ manifest->AddChild(permission_element);
+ }
+ }
+
+ printer.Print(StringPrintf("package: %s\n", manifest->package.data()));
+ ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
+ el->Print(printer);
+ });
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // Collect information about the resource configurations
+ if (apk_->GetResourceTable()) {
+ for (auto &package : apk_->GetResourceTable()->packages) {
+ for (auto &type : package->types) {
+ for (auto &entry : type->entries) {
+ for (auto &value : entry->values) {
+ std::string locale_str = value->config.GetBcp47LanguageTag();
+
+ // Collect all the unique locales of the apk
+ if (locales_.find(locale_str) == locales_.end()) {
+ ConfigDescription config = ManifestExtractor::DummyConfig();
+ config.setBcp47Locale(locale_str.data());
+ locales_.insert(std::make_pair(locale_str, config));
+ }
+
+ // Collect all the unique density of the apk
+ uint16_t density = (value->config.density == 0) ? (uint16_t) 160
+ : value->config.density;
+ if (densities_.find(density) == densities_.end()) {
+ ConfigDescription config = ManifestExtractor::DummyConfig();
+ config.density = density;
+ densities_.insert(std::make_pair(density, config));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Extract badging information
+ auto root = Visit(element);
+
+ // Print the elements in order seen
+ Print(root.get(), printer);
+
+ /** Recursively checks the extracted elements for the specified permission. **/
+ auto FindPermission = [&](ManifestExtractor::Element* root,
+ const std::string& name) -> ManifestExtractor::Element* {
+ return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
+ if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
+ return permission->name == name;
+ }
+ return false;
+ });
+ };
+
+ auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
+ int32_t max_sdk_version) -> void {
+ auto permission = util::make_unique<UsesPermission>();
+ permission->name = name;
+ permission->maxSdkVersion = max_sdk_version;
+ permission->Print(printer);
+ permission->PrintImplied(printer, reason);
+ };
+
+ // Implied permissions
+ // Pre-1.6 implicitly granted permission compatibility logic
+ CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
+ bool insert_write_external = false;
+ auto write_external_permission = ElementCast<UsesPermission>(
+ FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
+
+ if (target_sdk() < 4) {
+ if (!write_external_permission) {
+ PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
+ insert_write_external = true;
+ }
+
+ if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
+ PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
+ }
+ }
+
+ // If the application has requested WRITE_EXTERNAL_STORAGE, we will
+ // force them to always take READ_EXTERNAL_STORAGE as well. We always
+ // do this (regardless of target API version) because we can't have
+ // an app with write permission but not read permission.
+ auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
+ if (!read_external && (insert_write_external || write_external_permission)) {
+ PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
+ "requested WRITE_EXTERNAL_STORAGE",
+ (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
+ }
+
+ // Pre-JellyBean call log permission compatibility.
+ if (target_sdk() < 16) {
+ if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
+ && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
+ PrintPermission("android.permission.READ_CALL_LOG",
+ "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
+ }
+
+ if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
+ && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
+ PrintPermission("android.permission.WRITE_CALL_LOG",
+ "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
+ }
+ }
+
+ // If the app hasn't declared the touchscreen as a feature requirement (either
+ // directly or implied, required or not), then the faketouch feature is implied.
+ if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
+ common_feature_group->addImpliedFeature("android.hardware.faketouch",
+ "default feature for all apps", false);
+ }
+
+ // Only print the common feature group if no feature group is defined
+ std::vector<FeatureGroup*> feature_groups;
+ ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
+ if (auto feature_group = ElementCast<FeatureGroup>(el)) {
+ feature_groups.push_back(feature_group);
+ }
+ });
+
+ if (feature_groups.empty()) {
+ common_feature_group->PrintGroup(printer);
+ } else {
+ // Merge the common feature group into the feature group
+ for (auto& feature_group : feature_groups) {
+ feature_group->open_gles_version = std::max(feature_group->open_gles_version,
+ common_feature_group->open_gles_version);
+ feature_group->Merge(common_feature_group);
+ feature_group->PrintGroup(printer);
+ }
+ };
+
+ // Collect the component types of the application
+ std::set<std::string> components;
+ ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
+ if (ElementCast<Action>(el)) {
+ auto action = ElementCast<Action>(el);
+ if (!action->component.empty()) {
+ components.insert(action->component);
+ return;
+ }
+ }
+
+ if (ElementCast<Category>(el)) {
+ auto category = ElementCast<Category>(el);
+ if (!category->component.empty()) {
+ components.insert(category->component);
+ return;
+ }
+ }
+ });
+
+ // Check for the payment component
+ auto apk = apk_;
+ ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
+ if (auto service = ElementCast<Service>(el)) {
+ auto host_apdu_action = ElementCast<Action>(FindElement(service,
+ [&](ManifestExtractor::Element* el) -> bool {
+ if (auto action = ElementCast<Action>(el)) {
+ return (action->component == "host-apdu");
+ }
+ return false;
+ }));
+
+ auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
+ [&](ManifestExtractor::Element* el) -> bool {
+ if (auto action = ElementCast<Action>(el)) {
+ return (action->component == "offhost-apdu");
+ }
+ return false;
+ }));
+
+ ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
+ &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
+ if (auto meta_data = ElementCast<MetaData>(el)) {
+ if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
+ || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
+ && offhost_apdu_action)) {
+
+ // Attempt to load the resource file
+ if (!meta_data->resource) {
+ return;
+ }
+ auto resource = apk->LoadXml(*meta_data->resource, diag);
+ if (!resource) {
+ return;
+ }
+
+ // Look for the payment category on an <aid-group> element
+ auto& root = resource.get()->root;
+ if ((host_apdu_action && root->name == "host-apdu-service")
+ || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
+
+ for (auto& child : root->GetChildElements()) {
+ if (child->name == "aid-group") {
+ auto category = FindAttribute(child, CATEGORY_ATTR);
+ if (category && category->value == "payment") {
+ components.insert("payment");
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+ });
+
+ // Print the components types if they are present
+ auto PrintComponent = [&components, &printer](const std::string& component) -> void {
+ if (components.find(component) != components.end()) {
+ printer.Print(StringPrintf("provides-component:'%s'\n", component.data()));
+ }
+ };
+
+ PrintComponent("app-widget");
+ PrintComponent("device-admin");
+ PrintComponent("ime");
+ PrintComponent("wallpaper");
+ PrintComponent("accessibility");
+ PrintComponent("print-service");
+ PrintComponent("payment");
+ PrintComponent("search");
+ PrintComponent("document-provider");
+ PrintComponent("launcher");
+ PrintComponent("notification-listener");
+ PrintComponent("dream");
+ PrintComponent("camera");
+ PrintComponent("camera-secure");
+
+ // Print presence of main activity
+ if (components.find("main") != components.end()) {
+ printer.Print("main\n");
+ }
+
+ // Print presence of activities, recivers, and services with no special components
+ FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ if (auto activity = ElementCast<Activity>(el)) {
+ if (!activity->has_component_) {
+ printer.Print("other-activities\n");
+ return true;
+ }
+ }
+ return false;
+ });
+
+ FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ if (auto receiver = ElementCast<Receiver>(el)) {
+ if (!receiver->has_component) {
+ printer.Print("other-receivers\n");
+ return true;
+ }
+ }
+ return false;
+ });
+
+ FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ if (auto service = ElementCast<Service>(el)) {
+ if (!service->has_component) {
+ printer.Print("other-services\n");
+ return true;
+ }
+ }
+ return false;
+ });
+
+ // Print the supported screens
+ SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
+ [&](ManifestExtractor::Element* el) -> bool {
+ return ElementCast<SupportsScreen>(el) != nullptr;
+ }));
+
+ if (screen) {
+ screen->PrintScreens(printer, target_sdk_);
+ } else {
+ // Print the default supported screens
+ SupportsScreen default_screens;
+ default_screens.PrintScreens(printer, target_sdk_);
+ }
+
+ // Print all the unique locales of the apk
+ printer.Print("locales:");
+ for (auto& config : locales_) {
+ if (config.first.empty()) {
+ printer.Print(" '--_--'");
+ } else {
+ printer.Print(StringPrintf(" '%s'", config.first.data()));
+ }
+ }
+ printer.Print("\n");
+
+ // Print all the densities locales of the apk
+ printer.Print("densities:");
+ for (auto& config : densities_) {
+ printer.Print(StringPrintf(" '%d'", config.first));
+ }
+ printer.Print("\n");
+
+ // Print the supported architectures of the app
+ std::set<std::string> architectures;
+ auto it = apk_->GetFileCollection()->Iterator();
+ while (it->HasNext()) {
+ auto file_path = it->Next()->GetSource().path;
+
+
+ size_t pos = file_path.find("lib/");
+ if (pos != std::string::npos) {
+ file_path = file_path.substr(pos + 4);
+ pos = file_path.find("/");
+ if (pos != std::string::npos) {
+ file_path = file_path.substr(0, pos);
+ }
+
+ architectures.insert(file_path);
+ }
+ }
+
+ // Determine if the application has multiArch supports
+ auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto application = ElementCast<Application>(el)) {
+ return application->has_multi_arch;
+ }
+ return false;
+ });
+
+ bool output_alt_native_code = false;
+ // A multiArch package is one that contains 64-bit and
+ // 32-bit versions of native code and expects 3rd-party
+ // apps to load these native code libraries. Since most
+ // 64-bit systems also support 32-bit apps, the apps
+ // loading this multiArch package's code may be either
+ if (has_multi_arch) {
+ // If this is a multiArch package, report the 64-bit
+ // version only. Then as a separate entry, report the
+ // rest.
+ //
+ // If we report the 32-bit architecture, this APK will
+ // be installed on a 32-bit device, causing a large waste
+ // of bandwidth and disk space. This assumes that
+ // the developer of the multiArch package has also
+ // made a version that is 32-bit only.
+ const std::string kIntel64 = "x86_64";
+ const std::string kArm64 = "arm64-v8a";
+
+ auto arch = architectures.find(kIntel64);
+ if (arch == architectures.end()) {
+ arch = architectures.find(kArm64);
+ }
+
+ if (arch != architectures.end()) {
+ printer.Print(StringPrintf("native-code: '%s'\n", arch->data()));
+ architectures.erase(arch);
+ output_alt_native_code = true;
+ }
+ }
+
+ if (architectures.size() > 0) {
+ if (output_alt_native_code) {
+ printer.Print("alt-");
+ }
+ printer.Print("native-code:");
+ for (auto& arch : architectures) {
+ printer.Print(StringPrintf(" '%s'", arch.data()));
+ }
+ printer.Print("\n");
+ }
+
+ return true;
+}
+
+/**
+ * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
+ * pointer.
+ **/
+template<typename T>
+T* ElementCast(ManifestExtractor::Element* element) {
+ if (element == nullptr) {
+ return nullptr;
+ }
+
+ const std::unordered_map<std::string, bool> kTagCheck = {
+ {"action", std::is_base_of<Action, T>::value},
+ {"activity", std::is_base_of<Activity, T>::value},
+ {"application", std::is_base_of<Application, T>::value},
+ {"category", std::is_base_of<Category, T>::value},
+ {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
+ {"feature-group", std::is_base_of<FeatureGroup, T>::value},
+ {"input-type", std::is_base_of<InputType, T>::value},
+ {"intent-filter", std::is_base_of<IntentFilter, T>::value},
+ {"meta-data", std::is_base_of<MetaData, T>::value},
+ {"manifest", std::is_base_of<Manifest, T>::value},
+ {"original-package", std::is_base_of<OriginalPackage, T>::value},
+ {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
+ {"permission", std::is_base_of<Permission, T>::value},
+ {"provider", std::is_base_of<Provider, T>::value},
+ {"receiver", std::is_base_of<Receiver, T>::value},
+ {"screen", std::is_base_of<Screen, T>::value},
+ {"service", std::is_base_of<Service, T>::value},
+ {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
+ {"supports-input", std::is_base_of<SupportsInput, T>::value},
+ {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
+ {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
+ {"uses-feature", std::is_base_of<UsesFeature, T>::value},
+ {"uses-permission", std::is_base_of<UsesPermission, T>::value},
+ {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
+ {"uses-library", std::is_base_of<UsesLibrary, T>::value},
+ {"uses-package", std::is_base_of<UsesPackage, T>::value},
+ {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
+ };
+
+ auto check = kTagCheck.find(element->tag());
+ if (check != kTagCheck.end() && check->second) {
+ return static_cast<T*>(element);
+ }
+ return nullptr;
+}
+
+template<typename T>
+std::unique_ptr<T> CreateType() {
+ return std::move(util::make_unique<T>());
+}
+
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
+ ManifestExtractor* extractor, xml::Element* el) {
+ const std::unordered_map<std::string,
+ std::function<std::unique_ptr<ManifestExtractor::Element>()>>
+ kTagCheck = {
+ {"action", &CreateType<Action>},
+ {"activity", &CreateType<Activity>},
+ {"application", &CreateType<Application>},
+ {"category", &CreateType<Category>},
+ {"compatible-screens", &CreateType<CompatibleScreens>},
+ {"feature-group", &CreateType<FeatureGroup>},
+ {"input-type", &CreateType<InputType>},
+ {"intent-filter",&CreateType<IntentFilter>},
+ {"manifest", &CreateType<Manifest>},
+ {"meta-data", &CreateType<MetaData>},
+ {"original-package", &CreateType<OriginalPackage>},
+ {"package-verifier", &CreateType<PackageVerifier>},
+ {"permission", &CreateType<Permission>},
+ {"provider", &CreateType<Provider>},
+ {"receiver", &CreateType<Receiver>},
+ {"screen", &CreateType<Screen>},
+ {"service", &CreateType<Service>},
+ {"supports-gl-texture", &CreateType<SupportsGlTexture>},
+ {"supports-input", &CreateType<SupportsInput>},
+ {"supports-screens", &CreateType<SupportsScreen>},
+ {"uses-configuration", &CreateType<UsesConfiguarion>},
+ {"uses-feature", &CreateType<UsesFeature>},
+ {"uses-permission", &CreateType<UsesPermission>},
+ {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
+ {"uses-library", &CreateType<UsesLibrary>},
+ {"uses-package", &CreateType<UsesPackage>},
+ {"uses-sdk", &CreateType<UsesSdkBadging>},
+ };
+
+ // Attempt to map the xml tag to a element inflater
+ std::unique_ptr<ManifestExtractor::Element> element;
+ auto check = kTagCheck.find(el->name);
+ if (check != kTagCheck.end()) {
+ element = check->second();
+ } else {
+ element = util::make_unique<ManifestExtractor::Element>();
+ }
+
+ element->extractor_ = extractor;
+ element->tag_ = el->name;
+ element->Extract(el);
+ return element;
+}
+
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
+ auto element = ManifestExtractor::Element::Inflate(this, el);
+ parent_stack_.insert(parent_stack_.begin(), element.get());
+
+ // Process the element and recursively visit the children
+ for (xml::Element* child : el->GetChildElements()) {
+ auto v = Visit(child);
+ element->AddChild(v);
+ }
+
+ parent_stack_.erase(parent_stack_.begin());
+ return element;
+}
+
+// Use a smaller buffer so that there is less latency for dumping to stdout.
+constexpr size_t kStdOutBufferSize = 1024u;
+
+int DumpBadgingCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() < 1) {
+ diag_->Error(DiagMessage() << "No dump apk specified.");
+ return 1;
+ }
+
+ ManifestExtractor::Options options;
+ options.include_meta_data = include_metadata_;
+
+ io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ text::Printer printer(&fout);
+ for (auto apk : args) {
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+ if (!loaded_apk) {
+ return 1;
+ }
+
+ ManifestExtractor extractor(loaded_apk.get(), options);
+ extractor.Dump(printer, diag_);
+ }
+
+ return 0;
+}
+
+int DumpPermissionsCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() < 1) {
+ diag_->Error(DiagMessage() << "No dump apk specified.");
+ return 1;
+ }
+
+ ManifestExtractor::Options options;
+ options.only_permissions = true;
+
+ io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ text::Printer printer(&fout);
+ for (auto apk : args) {
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+ if (!loaded_apk) {
+ return 1;
+ }
+
+ ManifestExtractor extractor(loaded_apk.get(), options);
+ extractor.Dump(printer, diag_);
+ }
+
+ return 0;
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
new file mode 100644
index 000000000000..a70be53fa070
--- /dev/null
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -0,0 +1,61 @@
+/*
+ * 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 AAPT2_DUMP_MANIFEST_H
+#define AAPT2_DUMP_MANIFEST_H
+
+#include <Diagnostics.h>
+#include <ValueVisitor.h>
+#include <io/ZipArchive.h>
+
+
+#include "cmd/Command.h"
+#include "process/IResourceTableConsumer.h"
+#include "text/Printer.h"
+#include "xml/XmlDom.h"
+
+namespace aapt {
+
+class DumpBadgingCommand : public Command {
+ public:
+ explicit DumpBadgingCommand(IDiagnostics* diag) : Command("badging"), diag_(diag) {
+ SetDescription("Print information extracted from the manifest of the APK.");
+ AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
+ &include_metadata_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ IDiagnostics* diag_;
+ bool include_metadata_ = false;
+};
+
+class DumpPermissionsCommand : public Command {
+ public:
+ explicit DumpPermissionsCommand(IDiagnostics* diag) : Command("permissions"), diag_(diag) {
+ SetDescription("Print the permissions extracted from the manifest of the APK.");
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ IDiagnostics* diag_;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_DUMP_MANIFEST_H \ No newline at end of file
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index e99174302d26..b5c330622c72 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -154,6 +154,12 @@ static void MarkNonPreferredDensitiesAsClaimed(
bool TableSplitter::VerifySplitConstraints(IAaptContext* context) {
bool error = false;
for (size_t i = 0; i < split_constraints_.size(); i++) {
+ if (split_constraints_[i].configs.size() == 0) {
+ // For now, treat this as a warning. We may consider aborting processing.
+ context->GetDiagnostics()->Warn(DiagMessage()
+ << "no configurations for constraint '"
+ << split_constraints_[i].name << "'");
+ }
for (size_t j = i + 1; j < split_constraints_.size(); j++) {
for (const ConfigDescription& config : split_constraints_[i].configs) {
if (split_constraints_[j].configs.find(config) != split_constraints_[j].configs.end()) {
diff --git a/tools/aapt2/split/TableSplitter.h b/tools/aapt2/split/TableSplitter.h
index 6aec2576261e..ed24bc3991b4 100644
--- a/tools/aapt2/split/TableSplitter.h
+++ b/tools/aapt2/split/TableSplitter.h
@@ -30,6 +30,7 @@ namespace aapt {
struct SplitConstraints {
std::set<ConfigDescription> configs;
+ std::string name;
};
struct TableSplitterOptions {
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index fd5262af6e48..be6e51050c86 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -204,6 +204,112 @@ class PostProcessingConfigurationBuilder {
configuration::PostProcessingConfiguration config_;
};
+class ConfigDescriptionBuilder {
+ public:
+ ConfigDescriptionBuilder() = default;
+
+ ConfigDescriptionBuilder& setMcc(uint16_t mcc) {
+ config_.mcc = mcc;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setMnc(uint16_t mnc) {
+ config_.mnc = mnc;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setLanguage(uint16_t language) {
+ config_.language[0] = language >> 8;
+ config_.language[1] = language & 0xff;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setCountry(uint16_t country) {
+ config_.country[0] = country >> 8;
+ config_.country[1] = country & 0xff;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setOrientation(uint8_t orientation) {
+ config_.orientation = orientation;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setTouchscreen(uint8_t touchscreen) {
+ config_.touchscreen = touchscreen;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setDensity(uint16_t density) {
+ config_.density = density;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setKeyboard(uint8_t keyboard) {
+ config_.keyboard = keyboard;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setNavigation(uint8_t navigation) {
+ config_.navigation = navigation;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setInputFlags(uint8_t inputFlags) {
+ config_.inputFlags = inputFlags;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setInputPad0(uint8_t inputPad0) {
+ config_.inputPad0 = inputPad0;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenWidth(uint16_t screenWidth) {
+ config_.screenWidth = screenWidth;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenHeight(uint16_t screenHeight) {
+ config_.screenHeight = screenHeight;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setSdkVersion(uint16_t sdkVersion) {
+ config_.sdkVersion = sdkVersion;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setMinorVersion(uint16_t minorVersion) {
+ config_.minorVersion = minorVersion;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenLayout(uint8_t screenLayout) {
+ config_.screenLayout = screenLayout;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setUiMode(uint8_t uiMode) {
+ config_.uiMode = uiMode;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setSmallestScreenWidthDp(uint16_t smallestScreenWidthDp) {
+ config_.smallestScreenWidthDp = smallestScreenWidthDp;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenWidthDp(uint16_t screenWidthDp) {
+ config_.screenWidthDp = screenWidthDp;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenHeightDp(uint16_t screenHeightDp) {
+ config_.screenHeightDp = screenHeightDp;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenLayout2(uint8_t screenLayout2) {
+ config_.screenLayout2 = screenLayout2;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setColorMode(uint8_t colorMode) {
+ config_.colorMode = colorMode;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setScreenConfigPad2(uint16_t screenConfigPad2) {
+ config_.screenConfigPad2 = screenConfigPad2;
+ return *this;
+ }
+ ConfigDescription Build() {
+ return config_;
+ }
+
+ private:
+ ConfigDescription config_;
+};
+
} // namespace test
} // namespace aapt
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index bb02deccb69a..b4dfac6c01c7 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -127,7 +127,7 @@ public abstract class ProvisioningCallback {
public static final int OSU_STATUS_SERVICE_PROVIDER_VERIFIED = 5;
/**
- * The status code for provisioning flow to indicate starting the SOAP exchange.
+ * The status code for provisioning flow to indicate starting the first SOAP exchange.
*/
public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6;
@@ -142,6 +142,11 @@ public abstract class ProvisioningCallback {
public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8;
/**
+ * The status code for provisioning flow to indicate starting the second SOAP exchange.
+ */
+ public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9;
+
+ /**
* Provisioning status for OSU failure
*
* @param status indicates error condition