diff options
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 & 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 |