diff options
152 files changed, 5658 insertions, 3557 deletions
diff --git a/Android.bp b/Android.bp index 611d4ba18367..fd1239cea337 100644 --- a/Android.bp +++ b/Android.bp @@ -535,24 +535,22 @@ gensrcs { name: "framework-javastream-protos", depfile: true, - tool_files: ["tools/genprotos.sh"], tools: [ "aprotoc", "protoc-gen-javastream", "soong_zip", ], - // TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can - // end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to - // the way sbox rewrites the command. See b/70221552. - cmd: "$(location tools/genprotos.sh) " + - " $(location aprotoc) " + - " $(location protoc-gen-javastream) " + - " $(location soong_zip) " + - " $(genDir) " + - " $(depfile) " + - " $(in) " + - " $(out)", + cmd: "mkdir -p $(genDir)/$(in) " + + "&& $(location aprotoc) " + + " --plugin=$(location protoc-gen-javastream) " + + " --dependency_out=$(depfile) " + + " --javastream_out=$(genDir)/$(in) " + + " -Iexternal/protobuf/src " + + " -I . " + + " $(in) " + + "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)", + srcs: [ "core/proto/**/*.proto", "libs/incident/**/*.proto", @@ -808,7 +806,6 @@ aidl_interface { enabled: true, }, }, - api_dir: "aidl/incremental", } gensrcs { @@ -952,7 +949,10 @@ framework_docs_only_args = " -android -manifest $(location core/res/AndroidManif "-overview $(location core/java/overview.html) " + // Federate Support Library references against local API file. "-federate SupportLib https://developer.android.com " + - "-federationapi SupportLib $(location :current-support-api) " + "-federationapi SupportLib $(location :current-support-api) " + + // Federate Support Library references against local API file. + "-federate AndroidX https://developer.android.com " + + "-federationapi AndroidX $(location :current-androidx-api) " framework_docs_only_libs = [ "voip-common", @@ -1063,6 +1063,7 @@ doc_defaults { "core/res/AndroidManifest.xml", "core/java/overview.html", ":current-support-api", + ":current-androidx-api", ], create_stubs: false, } diff --git a/api/current.txt b/api/current.txt index 010f383fb0ed..ee9363751a00 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3047,9 +3047,9 @@ package android.accounts { field public final String type; } - public class AccountAuthenticatorActivity extends android.app.Activity { - ctor public AccountAuthenticatorActivity(); - method public final void setAccountAuthenticatorResult(android.os.Bundle); + @Deprecated public class AccountAuthenticatorActivity extends android.app.Activity { + ctor @Deprecated public AccountAuthenticatorActivity(); + method @Deprecated public final void setAccountAuthenticatorResult(android.os.Bundle); } public class AccountAuthenticatorResponse implements android.os.Parcelable { @@ -34834,8 +34834,8 @@ package android.os { } public class Handler { - ctor public Handler(); - ctor public Handler(@Nullable android.os.Handler.Callback); + ctor @Deprecated public Handler(); + ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback); ctor public Handler(@NonNull android.os.Looper); ctor public Handler(@NonNull android.os.Looper, @Nullable android.os.Handler.Callback); method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper); @@ -36846,7 +36846,6 @@ package android.provider { method @WorkerThread public static boolean isBlocked(android.content.Context, String); method @WorkerThread public static int unblock(android.content.Context, String); field public static final String AUTHORITY = "com.android.blockednumber"; - field public static final android.net.Uri AUTHORITY_URI; } public static class BlockedNumberContract.BlockedNumbers { @@ -43869,6 +43868,7 @@ package android.telecom { field public static final int LOCAL = 2; // 0x2 field public static final int MISSED = 5; // 0x5 field public static final int OTHER = 9; // 0x9 + field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED"; field public static final int REJECTED = 6; // 0x6 field public static final int REMOTE = 3; // 0x3 field public static final int RESTRICTED = 8; // 0x8 @@ -44397,6 +44397,7 @@ package android.telephony { field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call"; field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool"; field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool"; + field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool"; field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool"; field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool"; field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool"; @@ -44413,7 +44414,7 @@ package android.telephony { field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int"; - field public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool"; + field @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool"; field public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool"; field public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool"; field public static final String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string"; diff --git a/api/system-current.txt b/api/system-current.txt index 412e0959570c..c13afb6137b9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -68,6 +68,7 @@ package android { field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER"; field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER"; field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE"; + field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED"; field public static final String FORCE_BACK = "android.permission.FORCE_BACK"; field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS"; @@ -77,6 +78,7 @@ package android { field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"; field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS"; field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"; + field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES"; field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST"; field public static final String HDMI_CEC = "android.permission.HDMI_CEC"; field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"; @@ -646,6 +648,15 @@ package android.app { method public boolean isStatusBarExpansionDisabled(); } + public class UiModeManager { + method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int); + field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED"; + field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED"; + field public static final int DEFAULT_PRIORITY = 0; // 0x0 + field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE"; + field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY"; + } + public final class Vr2dDisplayProperties implements android.os.Parcelable { ctor public Vr2dDisplayProperties(int, int, int); method public int describeContents(); @@ -1284,7 +1295,9 @@ package android.bluetooth { public final class BluetoothAdapter { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice); method public boolean disableBLE(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice); method public boolean enableBLE(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset(); @@ -6117,6 +6130,19 @@ package android.printservice.recommendation { package android.provider { + public class BlockedNumberContract { + field @NonNull public static final android.net.Uri AUTHORITY_URI; + field public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact"; + field public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number"; + field public static final String RES_BLOCK_STATUS = "block_status"; + field public static final int STATUS_BLOCKED_IN_LIST = 1; // 0x1 + field public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; // 0x5 + field public static final int STATUS_BLOCKED_PAYPHONE = 4; // 0x4 + field public static final int STATUS_BLOCKED_RESTRICTED = 2; // 0x2 + field public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; // 0x3 + field public static final int STATUS_NOT_BLOCKED = 0; // 0x0 + } + public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns { field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata"; field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata"; @@ -8119,6 +8145,7 @@ package android.telephony { field public static final int NUMBER_UNREACHABLE = 8; // 0x8 field public static final int OTASP_PROVISIONING_IN_PROCESS = 76; // 0x4c field public static final int OUTGOING_CANCELED = 44; // 0x2c + field public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80; // 0x50 field public static final int OUTGOING_FAILURE = 43; // 0x2b field public static final int OUT_OF_NETWORK = 11; // 0xb field public static final int OUT_OF_SERVICE = 18; // 0x12 @@ -8693,7 +8720,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetherApnRequired(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); method public boolean needsOtaServiceProvisioning(); @@ -8784,6 +8811,7 @@ package android.telephony { public class TelephonyRegistryManager { method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor); method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyCallStateChangedForAllSubscriptions(int, @Nullable String); method public void notifyCarrierNetworkChange(boolean); method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); diff --git a/api/test-current.txt b/api/test-current.txt index 19e12127c115..897e82558e2d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -420,6 +420,7 @@ package android.app { } public class UiModeManager { + method @RequiresPermission("android.permission.ENTER_CAR_MODE_PRIORITIZED") public void enableCarMode(@IntRange(from=0) int, int); method public boolean isNightModeLocked(); method public boolean isUiModeLocked(); } @@ -2358,6 +2359,11 @@ package android.print { package android.provider { + public interface AndroidDeviceConfig { + field public static final String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = "system_gestures_excluded_by_pre_q_sticky_immersive"; + field public static final String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp"; + } + public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns { field public static final String[] SYNC_WRITABLE_COLUMNS; } @@ -2393,13 +2399,13 @@ package android.provider { method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); + field public static final String NAMESPACE_ANDROID = "android"; field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; field public static final String NAMESPACE_PERMISSIONS = "permissions"; field public static final String NAMESPACE_PRIVACY = "privacy"; field public static final String NAMESPACE_ROLLBACK = "rollback"; field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; - field public static final String NAMESPACE_WINDOW_MANAGER = "android:window_manager"; } public static interface DeviceConfig.OnPropertiesChangedListener { @@ -2416,11 +2422,6 @@ package android.provider { method @Nullable public String getString(@NonNull String, @Nullable String); } - public static interface DeviceConfig.WindowManager { - field public static final String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = "system_gestures_excluded_by_pre_q_sticky_immersive"; - field public static final String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp"; - } - public final class MediaStore { method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException; diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp deleted file mode 100644 index f415f8f5dd75..000000000000 --- a/cmds/idmap/create.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include "idmap.h" - -#include <memory> -#include <androidfw/AssetManager.h> -#include <androidfw/ResourceTypes.h> -#include <androidfw/ZipFileRO.h> -#include <utils/String8.h> - -#include <fcntl.h> -#include <sys/file.h> -#include <sys/stat.h> - -using namespace android; - -namespace { - int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc) - { - std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(zip_path)); - if (zip.get() == NULL) { - return -1; - } - ZipEntryRO entry = zip->findEntryByName(entry_name); - if (entry == NULL) { - return -1; - } - if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) { - return -1; - } - zip->releaseEntry(entry); - return 0; - } - - int open_idmap(const char *path) - { - int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)); - if (fd == -1) { - ALOGD("error: open %s: %s\n", path, strerror(errno)); - goto fail; - } - if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { - ALOGD("error: fchmod %s: %s\n", path, strerror(errno)); - goto fail; - } - if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) { - ALOGD("error: flock %s: %s\n", path, strerror(errno)); - goto fail; - } - - return fd; -fail: - if (fd != -1) { - close(fd); - unlink(path); - } - return -1; - } - - int write_idmap(int fd, const uint32_t *data, size_t size) - { - if (lseek(fd, 0, SEEK_SET) < 0) { - return -1; - } - size_t bytesLeft = size; - while (bytesLeft > 0) { - ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft)); - if (w < 0) { - fprintf(stderr, "error: write: %s\n", strerror(errno)); - return -1; - } - bytesLeft -= static_cast<size_t>(w); - } - return 0; - } - - bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd) - { - static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES; - struct stat st; - if (fstat(idmap_fd, &st) == -1) { - return true; - } - if (st.st_size < static_cast<off_t>(N)) { - // file is empty or corrupt - return true; - } - - char buf[N]; - size_t bytesLeft = N; - if (lseek(idmap_fd, 0, SEEK_SET) < 0) { - return true; - } - for (;;) { - ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft)); - if (r < 0) { - return true; - } - bytesLeft -= static_cast<size_t>(r); - if (bytesLeft == 0) { - break; - } - if (r == 0) { - // "shouldn't happen" - return true; - } - } - - uint32_t version, cached_target_crc, cached_overlay_crc; - String8 cached_target_path, cached_overlay_path; - if (!ResTable::getIdmapInfo(buf, N, &version, &cached_target_crc, &cached_overlay_crc, - &cached_target_path, &cached_overlay_path)) { - return true; - } - - if (version != ResTable::IDMAP_CURRENT_VERSION) { - return true; - } - - if (cached_target_path != target_apk_path) { - return true; - } - if (cached_overlay_path != overlay_apk_path) { - return true; - } - - uint32_t actual_target_crc, actual_overlay_crc; - if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, - &actual_target_crc) == -1) { - return true; - } - if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, - &actual_overlay_crc) == -1) { - return true; - } - - return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc; - } - - bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_path) - { - struct stat st; - if (stat(idmap_path, &st) == -1) { - // non-existing idmap is always stale; on other errors, abort idmap generation - return errno == ENOENT; - } - - int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY)); - if (idmap_fd == -1) { - return false; - } - bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd); - close(idmap_fd); - return is_stale; - } - - int create_idmap(const char *target_apk_path, const char *overlay_apk_path, - uint32_t **data, size_t *size) - { - uint32_t target_crc, overlay_crc; - if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, - &target_crc) == -1) { - return -1; - } - if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, - &overlay_crc) == -1) { - return -1; - } - - AssetManager am; - bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc, - data, size); - return b ? 0 : -1; - } - - int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path, - int fd, bool check_if_stale) - { - if (check_if_stale) { - if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) { - // already up to date -- nothing to do - return 0; - } - } - - uint32_t *data = NULL; - size_t size; - - if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) { - return -1; - } - - if (write_idmap(fd, data, size) == -1) { - free(data); - return -1; - } - - free(data); - return 0; - } -} - -int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_path) -{ - if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) { - // already up to date -- nothing to do - return EXIT_SUCCESS; - } - - int fd = open_idmap(idmap_path); - if (fd == -1) { - return EXIT_FAILURE; - } - - int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false); - close(fd); - if (r != 0) { - unlink(idmap_path); - } - return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} - -int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd) -{ - return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ? - EXIT_SUCCESS : EXIT_FAILURE; -} - -int idmap_verify_fd(const char *target_apk_path, const char *overlay_apk_path, int fd) -{ - return !is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd) ? - EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp deleted file mode 100644 index 8f86ed8f7d32..000000000000 --- a/cmds/idmap/idmap.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "idmap.h" - -#include <private/android_filesystem_config.h> // for AID_SYSTEM - -#include <stdlib.h> -#include <string.h> - -namespace { - const char *usage = "NAME\n\ - idmap - create or display idmap files\n\ -\n\ -SYNOPSIS \n\ - idmap --help \n\ - idmap --fd target overlay fd \n\ - idmap --path target overlay idmap \n\ - idmap --scan target-package-name-to-look-for path-to-target-apk dir-to-hold-idmaps \\\ - dir-to-scan [additional-dir-to-scan [additional-dir-to-scan [...]]]\n\ - idmap --inspect idmap \n\ - idmap --verify target overlay fd \n\ -\n\ -DESCRIPTION \n\ - Idmap files play an integral part in the runtime resource overlay framework. An idmap \n\ - file contains a mapping of resource identifiers between overlay package and its target \n\ - package; this mapping is used during resource lookup. Idmap files also act as control \n\ - files by their existence: if not present, the corresponding overlay package is ignored \n\ - when the resource context is created. \n\ -\n\ - Idmap files are stored in /data/resource-cache. For each pair (target package, overlay \n\ - package), there exists exactly one idmap file, or none if the overlay should not be used. \n\ -\n\ -NOMENCLATURE \n\ - target: the original, non-overlay, package. Each target package may be associated with \n\ - any number of overlay packages. \n\ -\n\ - overlay: an overlay package. Each overlay package is associated with exactly one target \n\ - package, specified in the overlay's manifest using the <overlay target=\"...\"/> \n\ - tag. \n\ -\n\ -OPTIONS \n\ - --help: display this help \n\ -\n\ - --fd: create idmap for target package 'target' (path to apk) and overlay package 'overlay' \n\ - (path to apk); write results to file descriptor 'fd' (integer). This invocation \n\ - version is intended to be used by a parent process with higher privileges to call \n\ - idmap in a controlled way: the parent will open a suitable file descriptor, fork, \n\ - drop its privileges and exec. This tool will continue execution without the extra \n\ - privileges, but still have write access to a file it could not have opened on its \n\ - own. \n\ -\n\ - --path: create idmap for target package 'target' (path to apk) and overlay package \n\ - 'overlay' (path to apk); write results to 'idmap' (path). \n\ -\n\ - --scan: non-recursively search directory 'dir-to-scan' (path) for static overlay packages \n\ - with target package 'target-package-name-to-look-for' (package name) present at\n\ - 'path-to-target-apk' (path to apk). For each overlay package found, create an\n\ - idmap file in 'dir-to-hold-idmaps' (path). \n\ -\n\ - --inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\ - debug-friendly format. \n\ -\n\ - --verify: verify if idmap corresponding to file descriptor 'fd' (integer) is made from \n\ - target package 'target' (path to apk) and overlay package 'overlay'. \n\ -\n\ -EXAMPLES \n\ - Create an idmap file: \n\ -\n\ - $ adb shell idmap --path /system/app/target.apk \\ \n\ - /vendor/overlay/overlay.apk \\ \n\ - /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\ -\n\ - Display an idmap file: \n\ -\n\ - $ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\ - SECTION ENTRY VALUE COMMENT \n\ - IDMAP HEADER magic 0x706d6469 \n\ - base crc 0xb65a383f \n\ - overlay crc 0x7b9675e8 \n\ - base path .......... /path/to/target.apk \n\ - overlay path .......... /path/to/overlay.apk \n\ - DATA HEADER target pkg 0x0000007f \n\ - types count 0x00000003 \n\ - DATA BLOCK target type 0x00000002 \n\ - overlay type 0x00000002 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 drawable/drawable \n\ - DATA BLOCK target type 0x00000003 \n\ - overlay type 0x00000003 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 xml/integer \n\ - DATA BLOCK target type 0x00000004 \n\ - overlay type 0x00000004 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 raw/lorem_ipsum \n\ -\n\ - In this example, the overlay package provides three alternative resource values:\n\ - drawable/drawable, xml/integer, and raw/lorem_ipsum \n\ -\n\ -NOTES \n\ - This tool and its expected invocation from installd is modelled on dexopt."; - - bool verify_directory_readable(const char *path) - { - return access(path, R_OK | X_OK) == 0; - } - - bool verify_directory_writable(const char *path) - { - return access(path, W_OK) == 0; - } - - bool verify_file_readable(const char *path) - { - return access(path, R_OK) == 0; - } - - bool verify_root_or_system() - { - uid_t uid = getuid(); - gid_t gid = getgid(); - - return (uid == 0 && gid == 0) || (uid == AID_SYSTEM && gid == AID_SYSTEM); - } - - int maybe_create_fd(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_str) - { - // anyone (not just root or system) may do --fd -- the file has - // already been opened by someone else on our behalf - - char *endptr; - int idmap_fd = strtol(idmap_str, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "error: failed to parse file descriptor argument %s\n", idmap_str); - return -1; - } - - if (!verify_file_readable(target_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno)); - return -1; - } - - if (!verify_file_readable(overlay_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno)); - return -1; - } - - return idmap_create_fd(target_apk_path, overlay_apk_path, idmap_fd); - } - - int maybe_create_path(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_path) - { - if (!verify_root_or_system()) { - fprintf(stderr, "error: permission denied: not user root or user system\n"); - return -1; - } - - if (!verify_file_readable(target_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno)); - return -1; - } - - if (!verify_file_readable(overlay_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno)); - return -1; - } - - return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path); - } - - int maybe_verify_fd(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_str) - { - char *endptr; - int idmap_fd = strtol(idmap_str, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "error: failed to parse file descriptor argument %s\n", idmap_str); - return -1; - } - - if (!verify_file_readable(target_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno)); - return -1; - } - - if (!verify_file_readable(overlay_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno)); - return -1; - } - - return idmap_verify_fd(target_apk_path, overlay_apk_path, idmap_fd); - } - - int maybe_scan(const char *target_package_name, const char *target_apk_path, - const char *idmap_dir, const android::Vector<const char *> *overlay_dirs) - { - if (!verify_root_or_system()) { - fprintf(stderr, "error: permission denied: not user root or user system\n"); - return -1; - } - - if (!verify_file_readable(target_apk_path)) { - ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno)); - return -1; - } - - if (!verify_directory_writable(idmap_dir)) { - ALOGD("error: no write access to %s: %s\n", idmap_dir, strerror(errno)); - return -1; - } - - const size_t N = overlay_dirs->size(); - for (size_t i = 0; i < N; i++) { - const char *dir = overlay_dirs->itemAt(i); - if (!verify_directory_readable(dir)) { - ALOGD("error: no read access to %s: %s\n", dir, strerror(errno)); - return -1; - } - } - - return idmap_scan(target_package_name, target_apk_path, idmap_dir, overlay_dirs); - } - - int maybe_inspect(const char *idmap_path) - { - // anyone (not just root or system) may do --inspect - if (!verify_file_readable(idmap_path)) { - ALOGD("error: failed to read idmap %s: %s\n", idmap_path, strerror(errno)); - return -1; - } - return idmap_inspect(idmap_path); - } -} - -int main(int argc, char **argv) -{ -#if 0 - { - char buf[1024]; - buf[0] = '\0'; - for (int i = 0; i < argc; ++i) { - strncat(buf, argv[i], sizeof(buf) - 1); - strncat(buf, " ", sizeof(buf) - 1); - } - ALOGD("%s:%d: uid=%d gid=%d argv=%s\n", __FILE__, __LINE__, getuid(), getgid(), buf); - } -#endif - - if (argc == 2 && !strcmp(argv[1], "--help")) { - printf("%s\n", usage); - return 0; - } - - if (argc == 5 && !strcmp(argv[1], "--fd")) { - return maybe_create_fd(argv[2], argv[3], argv[4]); - } - - if (argc == 5 && !strcmp(argv[1], "--path")) { - return maybe_create_path(argv[2], argv[3], argv[4]); - } - - if (argc == 5 && !strcmp(argv[1], "--verify")) { - return maybe_verify_fd(argv[2], argv[3], argv[4]); - } - - if (argc >= 6 && !strcmp(argv[1], "--scan")) { - android::Vector<const char *> v; - for (int i = 5; i < argc; i++) { - v.push(argv[i]); - } - return maybe_scan(argv[2], argv[3], argv[4], &v); - } - - if (argc == 3 && !strcmp(argv[1], "--inspect")) { - return maybe_inspect(argv[2]); - } - - fprintf(stderr, "Usage: don't use this (cf dexopt usage).\n"); - return EXIT_FAILURE; -} diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h deleted file mode 100644 index 5962108c9f7e..000000000000 --- a/cmds/idmap/idmap.h +++ /dev/null @@ -1,38 +0,0 @@ - -#ifndef _IDMAP_H_ -#define _IDMAP_H_ - -#define LOG_TAG "idmap" - -#include <utils/Log.h> -#include <utils/Vector.h> - -#include <errno.h> -#include <stdio.h> - -#ifndef TEMP_FAILURE_RETRY -// Used to retry syscalls that can return EINTR. -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - -int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_path); - -int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd); - -int idmap_verify_fd(const char *target_apk_path, const char *overlay_apk_path, int fd); - -// Regarding target_package_name: the idmap_scan implementation should -// be able to extract this from the manifest in target_apk_path, -// simplifying the external API. -int idmap_scan(const char *target_package_name, const char *target_apk_path, - const char *idmap_dir, const android::Vector<const char *> *overlay_dirs); - -int idmap_inspect(const char *idmap_path); - -#endif // _IDMAP_H_ diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp deleted file mode 100644 index 20005e2766d8..000000000000 --- a/cmds/idmap/inspect.cpp +++ /dev/null @@ -1,313 +0,0 @@ -#include "idmap.h" - -#include <androidfw/AssetManager.h> -#include <androidfw/ResourceTypes.h> -#include <utils/ByteOrder.h> -#include <utils/String8.h> - -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> - -using namespace android; - -namespace { - static const uint32_t IDMAP_MAGIC = 0x504D4449; - static const size_t PATH_LENGTH = 256; - - void printe(const char *fmt, ...); - - class IdmapBuffer { - private: - const char* buf_; - size_t len_; - size_t pos_; - public: - IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {} - - ~IdmapBuffer() { - if (buf_ != MAP_FAILED) { - munmap(const_cast<char*>(buf_), len_); - } - } - - status_t init(const char *idmap_path) { - struct stat st; - int fd; - - if (stat(idmap_path, &st) < 0) { - printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno)); - return UNKNOWN_ERROR; - } - len_ = st.st_size; - if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) { - printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno)); - return UNKNOWN_ERROR; - } - if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { - close(fd); - printe("failed to mmap idmap: %s\n", strerror(errno)); - return UNKNOWN_ERROR; - } - close(fd); - return NO_ERROR; - } - - status_t nextUint32(uint32_t* i) { - if (!buf_) { - printe("failed to read next uint32_t: buffer not initialized\n"); - return UNKNOWN_ERROR; - } - - if (pos_ + sizeof(uint32_t) > len_) { - printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n", - pos_); - return UNKNOWN_ERROR; - } - - if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) { - printe("failed to read next uint32_t: not aligned on 4-byte boundary\n"); - return UNKNOWN_ERROR; - } - - *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_)); - pos_ += sizeof(uint32_t); - return NO_ERROR; - } - - status_t nextUint16(uint16_t* i) { - if (!buf_) { - printe("failed to read next uint16_t: buffer not initialized\n"); - return UNKNOWN_ERROR; - } - - if (pos_ + sizeof(uint16_t) > len_) { - printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n", - pos_); - return UNKNOWN_ERROR; - } - - if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) { - printe("failed to read next uint32_t: not aligned on 2-byte boundary\n"); - return UNKNOWN_ERROR; - } - - *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_)); - pos_ += sizeof(uint16_t); - return NO_ERROR; - } - - status_t nextPath(char *b) { - if (!buf_) { - printe("failed to read next path: buffer not initialized\n"); - return UNKNOWN_ERROR; - } - if (pos_ + PATH_LENGTH > len_) { - printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_); - return UNKNOWN_ERROR; - } - memcpy(b, buf_ + pos_, PATH_LENGTH); - pos_ += PATH_LENGTH; - return NO_ERROR; - } - }; - - void printe(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - - void print_header() { - printf("SECTION ENTRY VALUE COMMENT\n"); - } - - void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - printf("%-12s %-12s 0x%08x ", section, subsection, value); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - } - - void print_path(const char *section, const char *subsection, const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - printf("%-12s %-12s .......... ", section, subsection); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - } - - status_t resource_metadata(const AssetManager& am, uint32_t res_id, - String8 *package, String8 *type, String8 *name) { - const ResTable& rt = am.getResources(); - struct ResTable::resource_name data; - if (!rt.getResourceName(res_id, false, &data)) { - printe("failed to get resource name id=0x%08x\n", res_id); - return UNKNOWN_ERROR; - } - if (package != NULL) { - *package = String8(String16(data.package, data.packageLen)); - } - if (type != NULL) { - *type = String8(String16(data.type, data.typeLen)); - } - if (name != NULL) { - *name = String8(String16(data.name, data.nameLen)); - } - return NO_ERROR; - } - - status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) { - uint32_t i; - char path[PATH_LENGTH]; - - status_t err = buf.nextUint32(&i); - if (err != NO_ERROR) { - return err; - } - - if (i != IDMAP_MAGIC) { - printe("not an idmap file: actual magic constant 0x%08x does not match expected magic " - "constant 0x%08x\n", i, IDMAP_MAGIC); - return UNKNOWN_ERROR; - } - - print_header(); - print("IDMAP HEADER", "magic", i, ""); - - err = buf.nextUint32(&i); - if (err != NO_ERROR) { - return err; - } - print("", "version", i, ""); - - err = buf.nextUint32(&i); - if (err != NO_ERROR) { - return err; - } - print("", "base crc", i, ""); - - err = buf.nextUint32(&i); - if (err != NO_ERROR) { - return err; - } - print("", "overlay crc", i, ""); - - err = buf.nextPath(path); - if (err != NO_ERROR) { - // printe done from IdmapBuffer::nextPath - return err; - } - print_path("", "base path", "%s", path); - - if (!am.addAssetPath(String8(path), NULL)) { - printe("failed to add '%s' as asset path\n", path); - return UNKNOWN_ERROR; - } - - err = buf.nextPath(path); - if (err != NO_ERROR) { - // printe done from IdmapBuffer::nextPath - return err; - } - print_path("", "overlay path", "%s", path); - - return NO_ERROR; - } - - status_t parse_data(IdmapBuffer& buf, const AssetManager& am) { - const uint32_t packageId = am.getResources().getBasePackageId(0); - - uint16_t data16; - status_t err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), ""); - - err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - print("", "types count", static_cast<uint32_t>(data16), ""); - - uint32_t typeCount = static_cast<uint32_t>(data16); - while (typeCount > 0) { - typeCount--; - - err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - const uint32_t targetTypeId = static_cast<uint32_t>(data16); - print("DATA BLOCK", "target type", targetTypeId, ""); - - err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - print("", "overlay type", static_cast<uint32_t>(data16), ""); - - err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - const uint32_t entryCount = static_cast<uint32_t>(data16); - print("", "entry count", entryCount, ""); - - err = buf.nextUint16(&data16); - if (err != NO_ERROR) { - return err; - } - const uint32_t entryOffset = static_cast<uint32_t>(data16); - print("", "entry offset", entryOffset, ""); - - for (uint32_t i = 0; i < entryCount; i++) { - uint32_t data32; - err = buf.nextUint32(&data32); - if (err != NO_ERROR) { - return err; - } - - uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i); - String8 type; - String8 name; - err = resource_metadata(am, resID, NULL, &type, &name); - if (err != NO_ERROR) { - return err; - } - if (data32 != ResTable_type::NO_ENTRY) { - print("", "entry", data32, "%s/%s", type.string(), name.string()); - } - } - } - - return NO_ERROR; - } -} - -int idmap_inspect(const char *idmap_path) { - IdmapBuffer buf; - if (buf.init(idmap_path) < 0) { - // printe done from IdmapBuffer::init - return EXIT_FAILURE; - } - AssetManager am; - if (parse_idmap_header(buf, am) != NO_ERROR) { - // printe done from parse_idmap_header - return EXIT_FAILURE; - } - if (parse_data(buf, am) != NO_ERROR) { - // printe done from parse_data_header - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp deleted file mode 100644 index 847dda3df91f..000000000000 --- a/cmds/idmap/scan.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include <dirent.h> -#include <inttypes.h> -#include <sys/file.h> -#include <sys/stat.h> - -#include "idmap.h" - -#include <memory> -#include <androidfw/ResourceTypes.h> -#include <androidfw/StreamingZipInflater.h> -#include <androidfw/ZipFileRO.h> -#include <cutils/properties.h> -#include <private/android_filesystem_config.h> // for AID_SYSTEM -#include <utils/SortedVector.h> -#include <utils/String16.h> -#include <utils/String8.h> - -#define NO_OVERLAY_TAG (-1000) - -using namespace android; - -namespace { - struct Overlay { - Overlay() {} - Overlay(const String8& a, const String8& i, int p) : - apk_path(a), idmap_path(i), priority(p) {} - - bool operator<(Overlay const& rhs) const - { - return rhs.priority > priority; - } - - String8 apk_path; - String8 idmap_path; - int priority; - }; - - bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector) - { - // the file is opened for appending so that it doesn't get truncated - // before we can guarantee mutual exclusion via the flock - FILE* fout = fopen(filename, "a"); - if (fout == NULL) { - return false; - } - - if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) { - fclose(fout); - return false; - } - - if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) { - TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN)); - fclose(fout); - return false; - } - - for (size_t i = 0; i < overlayVector.size(); ++i) { - const Overlay& overlay = overlayVector[i]; - fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string()); - } - - TEMP_FAILURE_RETRY(fflush(fout)); - TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN)); - fclose(fout); - - // Make file world readable since Zygote (running as root) will read - // it when creating the initial AssetManger object - const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644 - if (chmod(filename, mode) == -1) { - unlink(filename); - return false; - } - - return true; - } - - String8 flatten_path(const char *path) - { - String16 tmp(path); - tmp.replaceAll('/', '@'); - return String8(tmp); - } - - bool check_property(String16 property, String16 value) { - char propBuf[PROPERTY_VALUE_MAX]; - property_get(String8(property).c_str(), propBuf, NULL); - return String8(value) == propBuf; - } - - int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name, - bool* is_static_overlay) - { - const size_t N = parser.getAttributeCount(); - String16 target; - int priority = -1; - String16 propName = String16(); - String16 propValue = String16(); - for (size_t i = 0; i < N; ++i) { - size_t len; - String16 key(parser.getAttributeName(i, &len)); - if (key == String16("targetPackage")) { - const char16_t *p = parser.getAttributeStringValue(i, &len); - if (p != NULL) { - target = String16(p, len); - } - } else if (key == String16("priority")) { - Res_value v; - if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) { - priority = v.data; - if (priority < 0 || priority > 9999) { - return -1; - } - } - } else if (key == String16("isStatic")) { - Res_value v; - if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) { - *is_static_overlay = (v.data != 0); - } - } else if (key == String16("requiredSystemPropertyName")) { - const char16_t *p = parser.getAttributeStringValue(i, &len); - if (p != NULL) { - propName = String16(p, len); - } - } else if (key == String16("requiredSystemPropertyValue")) { - const char16_t *p = parser.getAttributeStringValue(i, &len); - if (p != NULL) { - propValue = String16(p, len); - } - } - } - - // Note that conditional property enablement/exclusion only applies if - // the attribute is present. In its absence, all overlays are presumed enabled. - if (propName.size() > 0 && propValue.size() > 0) { - // if property set & equal to value, then include overlay - otherwise skip - if (!check_property(propName, propValue)) { - return NO_OVERLAY_TAG; - } - } - - if (target == String16(target_package_name)) { - return priority; - } - return NO_OVERLAY_TAG; - } - - int parse_manifest(const void *data, size_t size, const char *target_package_name) - { - ResXMLTree parser; - parser.setTo(data, size); - if (parser.getError() != NO_ERROR) { - ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError()); - return -1; - } - - ResXMLParser::event_code_t type; - bool is_static_overlay = false; - int priority = NO_OVERLAY_TAG; - do { - type = parser.next(); - if (type == ResXMLParser::START_TAG) { - size_t len; - String16 tag(parser.getElementName(&len)); - if (tag == String16("overlay")) { - priority = parse_overlay_tag(parser, target_package_name, &is_static_overlay); - break; - } - } - } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT); - - if (is_static_overlay) { - return priority; - } - return NO_OVERLAY_TAG; - } - - int parse_apk(const char *path, const char *target_package_name) - { - std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path)); - if (zip.get() == NULL) { - ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path); - return -1; - } - ZipEntryRO entry; - if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) { - ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__); - return -1; - } - uint32_t uncompLen = 0; - uint16_t method; - if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) { - ALOGW("%s: failed to read entry info\n", __FUNCTION__); - return -1; - } - if (method != ZipFileRO::kCompressDeflated) { - ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method); - return -1; - } - FileMap *dataMap = zip->createEntryFileMap(entry); - if (dataMap == NULL) { - ALOGW("%s: failed to create FileMap\n", __FUNCTION__); - return -1; - } - char *buf = new char[uncompLen]; - if (NULL == buf) { - ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen); - delete dataMap; - return -1; - } - StreamingZipInflater inflater(dataMap, uncompLen); - if (inflater.read(buf, uncompLen) < 0) { - ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen); - delete[] buf; - delete dataMap; - return -1; - } - - int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name); - delete[] buf; - delete dataMap; - return priority; - } -} - -int idmap_scan(const char *target_package_name, const char *target_apk_path, - const char *idmap_dir, const android::Vector<const char *> *overlay_dirs) -{ - String8 filename = String8(idmap_dir); - filename.appendPath("overlays.list"); - - SortedVector<Overlay> overlayVector; - const size_t N = overlay_dirs->size(); - for (size_t i = 0; i < N; ++i) { - const char *overlay_dir = overlay_dirs->itemAt(i); - DIR *dir = opendir(overlay_dir); - if (dir == NULL) { - return EXIT_FAILURE; - } - - struct dirent *dirent; - while ((dirent = readdir(dir)) != NULL) { - struct stat st; - char overlay_apk_path[PATH_MAX + 1]; - snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name); - if (stat(overlay_apk_path, &st) < 0) { - continue; - } - if (!S_ISREG(st.st_mode)) { - continue; - } - - int priority = parse_apk(overlay_apk_path, target_package_name); - if (priority < 0) { - continue; - } - - String8 idmap_path(idmap_dir); - idmap_path.appendPath(flatten_path(overlay_apk_path + 1)); - idmap_path.append("@idmap"); - - if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) { - ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n", - target_apk_path, overlay_apk_path, idmap_path.string()); - continue; - } - - Overlay overlay(String8(overlay_apk_path), idmap_path, priority); - overlayVector.add(overlay); - } - - closedir(dir); - } - - if (!writePackagesList(filename.string(), overlayVector)) { - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index cf286e662630..360ddd44955a 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -69,9 +69,11 @@ cc_defaults { "src/external/GpuStatsPuller.cpp", "src/external/Perfetto.cpp", "src/external/PowerStatsPuller.cpp", + "src/external/PullResultReceiver.cpp", "src/external/puller_util.cpp", "src/external/ResourceHealthManagerPuller.cpp", "src/external/StatsCallbackPuller.cpp", + "src/external/StatsCallbackPullerDeprecated.cpp", "src/external/StatsCompanionServicePuller.cpp", "src/external/StatsPuller.cpp", "src/external/StatsPullerManager.cpp", diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 2c325ba6ac0a..1fd3abfc5adc 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1293,7 +1293,11 @@ Status StatsService::registerPullerCallback(int32_t atomTag, Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs, int64_t timeoutNs, const std::vector<int32_t>& additiveFields, const sp<android::os::IPullAtomCallback>& pullerCallback) { + ENFORCE_UID(AID_SYSTEM); + VLOG("StatsService::registerPuller called."); + mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields, + pullerCallback); return Status::ok(); } diff --git a/cmds/statsd/src/external/PullResultReceiver.cpp b/cmds/statsd/src/external/PullResultReceiver.cpp new file mode 100644 index 000000000000..6bd05452f3b0 --- /dev/null +++ b/cmds/statsd/src/external/PullResultReceiver.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 "PullResultReceiver.h" + +using namespace android::binder; +using namespace android::util; +using namespace std; + +namespace android { +namespace os { +namespace statsd { + +PullResultReceiver::PullResultReceiver( + std::function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCb) + : pullFinishCallback(std::move(pullFinishCb)) { +} + +Status PullResultReceiver::pullFinished(int32_t atomTag, bool success, + const vector<StatsEvent>& output) { + pullFinishCallback(atomTag, success, output); + return Status::ok(); +} + +PullResultReceiver::~PullResultReceiver() { +} + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/external/PullResultReceiver.h b/cmds/statsd/src/external/PullResultReceiver.h new file mode 100644 index 000000000000..f731f778a337 --- /dev/null +++ b/cmds/statsd/src/external/PullResultReceiver.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 <android/os/BnPullAtomResultReceiver.h> + +using namespace std; + +namespace android { +namespace os { +namespace statsd { + +class PullResultReceiver : public BnPullAtomResultReceiver { +public: + PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> + pullFinishCallback); + ~PullResultReceiver(); + + /** + * Binder call for finishing a pull. + */ + binder::Status pullFinished(int32_t atomTag, bool success, + const vector<android::util::StatsEvent>& output) override; + +private: + function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCallback; +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp index d718273e9b85..92db68477dbd 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.cpp +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -17,21 +17,27 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include <android/os/IStatsPullerCallback.h> - #include "StatsCallbackPuller.h" + +#include <android/os/IPullAtomCallback.h> +#include <android/util/StatsEvent.h> + +#include "PullResultReceiver.h" +#include "StatsPullerManager.h" #include "logd/LogEvent.h" #include "stats_log_util.h" using namespace android::binder; +using namespace android::util; +using namespace std; namespace android { namespace os { namespace statsd { -StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback) : - StatsPuller(tagId), mCallback(callback) { - VLOG("StatsCallbackPuller created for tag %d", tagId); +StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback) + : StatsPuller(tagId), mCallback(callback) { + VLOG("StatsCallbackPuller created for tag %d", tagId); } bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { @@ -40,20 +46,57 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { ALOGW("No callback registered"); return false; } - int64_t wallClockTimeNs = getWallClockNs(); - int64_t elapsedTimeNs = getElapsedRealtimeNs(); - vector<StatsLogEventWrapper> returned_value; - Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value); + + // Shared variables needed in the result receiver. + shared_ptr<mutex> cv_mutex = make_shared<mutex>(); + shared_ptr<condition_variable> cv = make_shared<condition_variable>(); + shared_ptr<bool> pullFinish = make_shared<bool>(false); + shared_ptr<bool> pullSuccess = make_shared<bool>(false); + shared_ptr<vector<shared_ptr<LogEvent>>> sharedData = + make_shared<vector<shared_ptr<LogEvent>>>(); + + sp<PullResultReceiver> resultReceiver = new PullResultReceiver( + [cv_mutex, cv, pullFinish, pullSuccess, sharedData]( + int32_t atomTag, bool success, const vector<StatsEvent>& output) { + // This is the result of the pull, executing in a statsd binder thread. + // The pull could have taken a long time, and we should only modify + // data (the output param) if the pointer is in scope and the pull did not time out. + { + lock_guard<mutex> lk(*cv_mutex); + // TODO: fill the shared vector of LogEvents once StatsEvent is complete. + *pullSuccess = success; + *pullFinish = true; + } + cv->notify_one(); + }); + + // Initiate the pull. + Status status = mCallback->onPullAtom(mTagId, resultReceiver); if (!status.isOk()) { - ALOGW("StatsCallbackPuller::pull failed for %d", mTagId); return false; } - data->clear(); - for (const StatsLogEventWrapper& it: returned_value) { - LogEvent::createLogEvents(it, *data); + + { + unique_lock<mutex> unique_lk(*cv_mutex); + int64_t pullTimeoutNs = + StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).pullTimeoutNs; + // Wait until the pull finishes, or until the pull timeout. + cv->wait_for(unique_lk, chrono::nanoseconds(pullTimeoutNs), + [pullFinish] { return *pullFinish; }); + if (!*pullFinish) { + // Note: The parent stats puller will also note that there was a timeout and that the + // cache should be cleared. Once we migrate all pullers to this callback, we could + // consolidate the logic. + return true; + } else { + // Only copy the data if we did not timeout and the pull was successful. + if (pullSuccess) { + *data = std::move(*sharedData); + } + VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); + return *pullSuccess; + } } - VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); - return true; } } // namespace statsd diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h index c4bfa89ba9a7..ce506c7f9785 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.h +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -16,8 +16,9 @@ #pragma once -#include <android/os/IStatsPullerCallback.h> +#include <android/os/IPullAtomCallback.h> #include <utils/String16.h> + #include "StatsPuller.h" namespace android { @@ -26,11 +27,11 @@ namespace statsd { class StatsCallbackPuller : public StatsPuller { public: - explicit StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback); + explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback); private: bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; - const sp<IStatsPullerCallback> mCallback; + const sp<IPullAtomCallback> mCallback; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsCallbackPullerDeprecated.cpp b/cmds/statsd/src/external/StatsCallbackPullerDeprecated.cpp new file mode 100644 index 000000000000..4f88a91f9ec6 --- /dev/null +++ b/cmds/statsd/src/external/StatsCallbackPullerDeprecated.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 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 DEBUG false // STOPSHIP if true +#include "Log.h" + +#include "StatsCallbackPullerDeprecated.h" + +#include <android/os/IStatsPullerCallback.h> + +#include "logd/LogEvent.h" +#include "stats_log_util.h" + +using namespace android::binder; + +namespace android { +namespace os { +namespace statsd { + +StatsCallbackPullerDeprecated::StatsCallbackPullerDeprecated( + int tagId, const sp<IStatsPullerCallback>& callback) + : StatsPuller(tagId), mCallback(callback) { + VLOG("StatsCallbackPuller created for tag %d", tagId); +} + +bool StatsCallbackPullerDeprecated::PullInternal(vector<shared_ptr<LogEvent>>* data) { + VLOG("StatsCallbackPuller called for tag %d", mTagId) + if (mCallback == nullptr) { + ALOGW("No callback registered"); + return false; + } + int64_t wallClockTimeNs = getWallClockNs(); + int64_t elapsedTimeNs = getElapsedRealtimeNs(); + vector<StatsLogEventWrapper> returned_value; + Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value); + if (!status.isOk()) { + ALOGW("StatsCallbackPuller::pull failed for %d", mTagId); + return false; + } + data->clear(); + for (const StatsLogEventWrapper& it : returned_value) { + LogEvent::createLogEvents(it, *data); + } + VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId); + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/services/tests/servicestests/src/com/android/server/pm/UserTests.java b/cmds/statsd/src/external/StatsCallbackPullerDeprecated.h index 525382d50d72..028902975923 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserTests.java +++ b/cmds/statsd/src/external/StatsCallbackPullerDeprecated.h @@ -14,24 +14,26 @@ * limitations under the License. */ -package com.android.server.pm; +#pragma once -import org.junit.runner.RunWith; -import org.junit.runners.Suite; +#include <android/os/IStatsPullerCallback.h> +#include <utils/String16.h> -@RunWith(Suite.class) -@Suite.SuiteClasses({ - UserDataPreparerTest.class, - UserLifecycleStressTest.class, - UserManagerServiceCreateProfileTest.class, - UserManagerServiceIdRecyclingTest.class, - UserManagerServiceTest.class, - UserManagerServiceUserInfoTest.class, - UserManagerServiceUserTypeTest.class, - UserManagerTest.class, - UserRestrictionsUtilsTest.class, - UserSystemPackageInstallerTest.class, -}) -public class UserTests { -} +#include "StatsPuller.h" +namespace android { +namespace os { +namespace statsd { + +class StatsCallbackPullerDeprecated : public StatsPuller { +public: + explicit StatsCallbackPullerDeprecated(int tagId, const sp<IStatsPullerCallback>& callback); + +private: + bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; + const sp<IStatsPullerCallback> mCallback; +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 9552c0a5e35e..3c6bc2db1d62 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -40,8 +40,9 @@ bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { lock_guard<std::mutex> lock(mLock); int64_t elapsedTimeNs = getElapsedRealtimeNs(); StatsdStats::getInstance().notePull(mTagId); - const bool shouldUseCache = elapsedTimeNs - mLastPullTimeNs < - StatsPullerManager::kAllPullAtomInfo.at(mTagId).coolDownNs; + const bool shouldUseCache = + elapsedTimeNs - mLastPullTimeNs < + StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).coolDownNs; if (shouldUseCache) { if (mHasGoodData) { (*data) = mCachedData; @@ -63,7 +64,8 @@ bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { const int64_t pullDurationNs = getElapsedRealtimeNs() - elapsedTimeNs; StatsdStats::getInstance().notePullTime(mTagId, pullDurationNs); const bool pullTimeOut = - pullDurationNs > StatsPullerManager::kAllPullAtomInfo.at(mTagId).pullTimeoutNs; + pullDurationNs > + StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).pullTimeoutNs; if (pullTimeOut) { // Something went wrong. Discard the data. clearCacheLocked(); @@ -100,7 +102,7 @@ int StatsPuller::clearCacheLocked() { int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) { if (timestampNs - mLastPullTimeNs > - StatsPullerManager::kAllPullAtomInfo.at(mTagId).coolDownNs) { + StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).coolDownNs) { return clearCache(); } else { return 0; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 535fcfbfc454..ce27ce6853e8 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -19,6 +19,7 @@ #include "StatsPullerManager.h" +#include <android/os/IPullAtomCallback.h> #include <android/os/IStatsCompanionService.h> #include <android/os/IStatsPullerCallback.h> #include <cutils/log.h> @@ -37,6 +38,7 @@ #include "PowerStatsPuller.h" #include "ResourceHealthManagerPuller.h" #include "StatsCallbackPuller.h" +#include "StatsCallbackPullerDeprecated.h" #include "StatsCompanionServicePuller.h" #include "SubsystemSleepStatePuller.h" #include "SurfaceflingerStatsPuller.h" @@ -57,224 +59,226 @@ namespace statsd { // Values smaller than this may require to update the alarm. const int64_t NO_ALARM_UPDATE = INT64_MAX; -std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { +std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // wifi_bytes_transfer - {android::util::WIFI_BYTES_TRANSFER, + {{.atomTag = android::util::WIFI_BYTES_TRANSFER}, {.additiveFields = {2, 3, 4, 5}, .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}}, // wifi_bytes_transfer_by_fg_bg - {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, + {{.atomTag = android::util::WIFI_BYTES_TRANSFER_BY_FG_BG}, {.additiveFields = {3, 4, 5, 6}, .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, // mobile_bytes_transfer - {android::util::MOBILE_BYTES_TRANSFER, + {{.atomTag = android::util::MOBILE_BYTES_TRANSFER}, {.additiveFields = {2, 3, 4, 5}, .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, // mobile_bytes_transfer_by_fg_bg - {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, + {{.atomTag = android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG}, {.additiveFields = {3, 4, 5, 6}, .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, // bluetooth_bytes_transfer - {android::util::BLUETOOTH_BYTES_TRANSFER, + {{.atomTag = android::util::BLUETOOTH_BYTES_TRANSFER}, {.additiveFields = {2, 3}, .puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, // kernel_wakelock - {android::util::KERNEL_WAKELOCK, + {{.atomTag = android::util::KERNEL_WAKELOCK}, {.puller = new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, // subsystem_sleep_state - {android::util::SUBSYSTEM_SLEEP_STATE, {.puller = new SubsystemSleepStatePuller()}}, + {{.atomTag = android::util::SUBSYSTEM_SLEEP_STATE}, + {.puller = new SubsystemSleepStatePuller()}}, // on_device_power_measurement - {android::util::ON_DEVICE_POWER_MEASUREMENT, {.puller = new PowerStatsPuller()}}, + {{.atomTag = android::util::ON_DEVICE_POWER_MEASUREMENT}, + {.puller = new PowerStatsPuller()}}, // cpu_time_per_freq - {android::util::CPU_TIME_PER_FREQ, + {{.atomTag = android::util::CPU_TIME_PER_FREQ}, {.additiveFields = {3}, .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, // cpu_time_per_uid - {android::util::CPU_TIME_PER_UID, + {{.atomTag = android::util::CPU_TIME_PER_UID}, {.additiveFields = {2, 3}, .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, // cpu_time_per_uid_freq // the throttling is 3sec, handled in // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader - {android::util::CPU_TIME_PER_UID_FREQ, + {{.atomTag = android::util::CPU_TIME_PER_UID_FREQ}, {.additiveFields = {4}, .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, // cpu_active_time // the throttling is 3sec, handled in // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader - {android::util::CPU_ACTIVE_TIME, + {{.atomTag = android::util::CPU_ACTIVE_TIME}, {.additiveFields = {2}, .puller = new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, // cpu_cluster_time // the throttling is 3sec, handled in // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader - {android::util::CPU_CLUSTER_TIME, + {{.atomTag = android::util::CPU_CLUSTER_TIME}, {.additiveFields = {3}, .puller = new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, // wifi_activity_energy_info - {android::util::WIFI_ACTIVITY_INFO, + {{.atomTag = android::util::WIFI_ACTIVITY_INFO}, {.puller = new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}}, // modem_activity_info - {android::util::MODEM_ACTIVITY_INFO, + {{.atomTag = android::util::MODEM_ACTIVITY_INFO}, {.puller = new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, // bluetooth_activity_info - {android::util::BLUETOOTH_ACTIVITY_INFO, + {{.atomTag = android::util::BLUETOOTH_ACTIVITY_INFO}, {.puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, // system_elapsed_realtime - {android::util::SYSTEM_ELAPSED_REALTIME, + {{.atomTag = android::util::SYSTEM_ELAPSED_REALTIME}, {.coolDownNs = NS_PER_SEC, .puller = new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME), .pullTimeoutNs = NS_PER_SEC / 2, }}, // system_uptime - {android::util::SYSTEM_UPTIME, + {{.atomTag = android::util::SYSTEM_UPTIME}, {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, // remaining_battery_capacity - {android::util::REMAINING_BATTERY_CAPACITY, + {{.atomTag = android::util::REMAINING_BATTERY_CAPACITY}, {.puller = new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, // full_battery_capacity - {android::util::FULL_BATTERY_CAPACITY, + {{.atomTag = android::util::FULL_BATTERY_CAPACITY}, {.puller = new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, // battery_voltage - {android::util::BATTERY_VOLTAGE, + {{.atomTag = android::util::BATTERY_VOLTAGE}, {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}}, // battery_level - {android::util::BATTERY_LEVEL, + {{.atomTag = android::util::BATTERY_LEVEL}, {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}}, // battery_cycle_count - {android::util::BATTERY_CYCLE_COUNT, + {{.atomTag = android::util::BATTERY_CYCLE_COUNT}, {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}}, // process_memory_state - {android::util::PROCESS_MEMORY_STATE, + {{.atomTag = android::util::PROCESS_MEMORY_STATE}, {.additiveFields = {4, 5, 6, 7, 8}, .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, // process_memory_high_water_mark - {android::util::PROCESS_MEMORY_HIGH_WATER_MARK, + {{.atomTag = android::util::PROCESS_MEMORY_HIGH_WATER_MARK}, {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, // process_memory_snapshot - {android::util::PROCESS_MEMORY_SNAPSHOT, + {{.atomTag = android::util::PROCESS_MEMORY_SNAPSHOT}, {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}}, // system_ion_heap_size - {android::util::SYSTEM_ION_HEAP_SIZE, + {{.atomTag = android::util::SYSTEM_ION_HEAP_SIZE}, {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}}, // process_system_ion_heap_size - {android::util::PROCESS_SYSTEM_ION_HEAP_SIZE, + {{.atomTag = android::util::PROCESS_SYSTEM_ION_HEAP_SIZE}, {.puller = new StatsCompanionServicePuller(android::util::PROCESS_SYSTEM_ION_HEAP_SIZE)}}, // temperature - {android::util::TEMPERATURE, + {{.atomTag = android::util::TEMPERATURE}, {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}}, // cooling_device - {android::util::COOLING_DEVICE, + {{.atomTag = android::util::COOLING_DEVICE}, {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}}, // binder_calls - {android::util::BINDER_CALLS, + {{.atomTag = android::util::BINDER_CALLS}, {.additiveFields = {4, 5, 6, 8, 12}, .puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS)}}, // binder_calls_exceptions - {android::util::BINDER_CALLS_EXCEPTIONS, + {{.atomTag = android::util::BINDER_CALLS_EXCEPTIONS}, {.puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}}, // looper_stats - {android::util::LOOPER_STATS, + {{.atomTag = android::util::LOOPER_STATS}, {.additiveFields = {5, 6, 7, 8, 9}, .puller = new StatsCompanionServicePuller(android::util::LOOPER_STATS)}}, // Disk Stats - {android::util::DISK_STATS, + {{.atomTag = android::util::DISK_STATS}, {.puller = new StatsCompanionServicePuller(android::util::DISK_STATS)}}, // Directory usage - {android::util::DIRECTORY_USAGE, + {{.atomTag = android::util::DIRECTORY_USAGE}, {.puller = new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}}, // Size of app's code, data, and cache - {android::util::APP_SIZE, + {{.atomTag = android::util::APP_SIZE}, {.puller = new StatsCompanionServicePuller(android::util::APP_SIZE)}}, // Size of specific categories of files. Eg. Music. - {android::util::CATEGORY_SIZE, + {{.atomTag = android::util::CATEGORY_SIZE}, {.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, // Number of fingerprints enrolled for each user. - {android::util::NUM_FINGERPRINTS_ENROLLED, + {{.atomTag = android::util::NUM_FINGERPRINTS_ENROLLED}, {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS_ENROLLED)}}, // Number of faces enrolled for each user. - {android::util::NUM_FACES_ENROLLED, + {{.atomTag = android::util::NUM_FACES_ENROLLED}, {.puller = new StatsCompanionServicePuller(android::util::NUM_FACES_ENROLLED)}}, // ProcStats. - {android::util::PROC_STATS, + {{.atomTag = android::util::PROC_STATS}, {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}}, // ProcStatsPkgProc. - {android::util::PROC_STATS_PKG_PROC, + {{.atomTag = android::util::PROC_STATS_PKG_PROC}, {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}}, // Disk I/O stats per uid. - {android::util::DISK_IO, + {{.atomTag = android::util::DISK_IO}, {.additiveFields = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, .coolDownNs = 3 * NS_PER_SEC, .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}}, // PowerProfile constants for power model calculations. - {android::util::POWER_PROFILE, + {{.atomTag = android::util::POWER_PROFILE}, {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. - {android::util::PROCESS_CPU_TIME, + {{.atomTag = android::util::PROCESS_CPU_TIME}, {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/, .puller = new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}}, - {android::util::CPU_TIME_PER_THREAD_FREQ, + {{.atomTag = android::util::CPU_TIME_PER_THREAD_FREQ}, {.additiveFields = {7, 9, 11, 13, 15, 17, 19, 21}, .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}}, // DeviceCalculatedPowerUse. - {android::util::DEVICE_CALCULATED_POWER_USE, + {{.atomTag = android::util::DEVICE_CALCULATED_POWER_USE}, {.puller = new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}}, // DeviceCalculatedPowerBlameUid. - {android::util::DEVICE_CALCULATED_POWER_BLAME_UID, + {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_UID}, {.puller = new StatsCompanionServicePuller( android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}}, // DeviceCalculatedPowerBlameOther. - {android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER, + {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER}, {.puller = new StatsCompanionServicePuller( android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}}, // DebugElapsedClock. - {android::util::DEBUG_ELAPSED_CLOCK, + {{.atomTag = android::util::DEBUG_ELAPSED_CLOCK}, {.additiveFields = {1, 2, 3, 4}, .puller = new StatsCompanionServicePuller(android::util::DEBUG_ELAPSED_CLOCK)}}, // DebugFailingElapsedClock. - {android::util::DEBUG_FAILING_ELAPSED_CLOCK, + {{.atomTag = android::util::DEBUG_FAILING_ELAPSED_CLOCK}, {.additiveFields = {1, 2, 3, 4}, .puller = new StatsCompanionServicePuller(android::util::DEBUG_FAILING_ELAPSED_CLOCK)}}, // BuildInformation. - {android::util::BUILD_INFORMATION, + {{.atomTag = android::util::BUILD_INFORMATION}, {.puller = new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}}, // RoleHolder. - {android::util::ROLE_HOLDER, + {{.atomTag = android::util::ROLE_HOLDER}, {.puller = new StatsCompanionServicePuller(android::util::ROLE_HOLDER)}}, // PermissionState. - {android::util::DANGEROUS_PERMISSION_STATE, + {{.atomTag = android::util::DANGEROUS_PERMISSION_STATE}, {.puller = new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE)}}, // TrainInfo. - {android::util::TRAIN_INFO, {.puller = new TrainInfoPuller()}}, + {{.atomTag = android::util::TRAIN_INFO}, {.puller = new TrainInfoPuller()}}, // TimeZoneDataInfo. - {android::util::TIME_ZONE_DATA_INFO, + {{.atomTag = android::util::TIME_ZONE_DATA_INFO}, {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}}, // ExternalStorageInfo - {android::util::EXTERNAL_STORAGE_INFO, + {{.atomTag = android::util::EXTERNAL_STORAGE_INFO}, {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}}, // GpuStatsGlobalInfo - {android::util::GPU_STATS_GLOBAL_INFO, + {{.atomTag = android::util::GPU_STATS_GLOBAL_INFO}, {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}}, // GpuStatsAppInfo - {android::util::GPU_STATS_APP_INFO, + {{.atomTag = android::util::GPU_STATS_APP_INFO}, {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}}, // AppsOnExternalStorageInfo - {android::util::APPS_ON_EXTERNAL_STORAGE_INFO, + {{.atomTag = android::util::APPS_ON_EXTERNAL_STORAGE_INFO}, {.puller = new StatsCompanionServicePuller(android::util::APPS_ON_EXTERNAL_STORAGE_INFO)}}, // Face Settings - {android::util::FACE_SETTINGS, + {{.atomTag = android::util::FACE_SETTINGS}, {.puller = new StatsCompanionServicePuller(android::util::FACE_SETTINGS)}}, // App ops - {android::util::APP_OPS, + {{.atomTag = android::util::APP_OPS}, {.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}}, // SurfaceflingerStatsGlobalInfo - {android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, + {{.atomTag = android::util::SURFACEFLINGER_STATS_GLOBAL_INFO}, {.puller = new SurfaceflingerStatsPuller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)}}, // VmsClientStats - {android::util::VMS_CLIENT_STATS, + {{.atomTag = android::util::VMS_CLIENT_STATS}, {.additiveFields = {5, 6, 7, 8, 9, 10}, .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}}, }; @@ -285,8 +289,8 @@ StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) { VLOG("Initiating pulling %d", tagId); - if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) { - bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data); + if (kAllPullAtomInfo.find({.atomTag = tagId}) != kAllPullAtomInfo.end()) { + bool ret = kAllPullAtomInfo.find({.atomTag = tagId})->second.puller->Pull(data); VLOG("pulled %d items", (int)data->size()); if (!ret) { StatsdStats::getInstance().notePullFailed(tagId); @@ -300,7 +304,8 @@ bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) { bool StatsPullerManager::PullerForMatcherExists(int tagId) const { // Vendor pulled atoms might be registered after we parse the config. - return isVendorPulledAtom(tagId) || kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end(); + return isVendorPulledAtom(tagId) || + kAllPullAtomInfo.find({.atomTag = tagId}) != kAllPullAtomInfo.end(); } void StatsPullerManager::updateAlarmLocked() { @@ -469,6 +474,7 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) { return totalCleared; } +// Deprecated, remove after puller API is complete. void StatsPullerManager::RegisterPullerCallback(int32_t atomTag, const sp<IStatsPullerCallback>& callback) { AutoMutex _l(mLock); @@ -479,7 +485,22 @@ void StatsPullerManager::RegisterPullerCallback(int32_t atomTag, } VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); - kAllPullAtomInfo[atomTag] = {.puller = new StatsCallbackPuller(atomTag, callback)}; + kAllPullAtomInfo[{.atomTag = atomTag}] = { + .puller = new StatsCallbackPullerDeprecated(atomTag, callback)}; +} + +void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t atomTag, + const int64_t coolDownNs, const int64_t timeoutNs, + const vector<int32_t>& additiveFields, + const sp<IPullAtomCallback>& callback) { + AutoMutex _l(mLock); + VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); + // TODO: linkToDeath with the callback so that we can remove it and delete the puller. + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); + kAllPullAtomInfo[{.atomTag = atomTag}] = {.additiveFields = additiveFields, + .coolDownNs = coolDownNs, + .pullTimeoutNs = timeoutNs, + .puller = new StatsCallbackPuller(atomTag, callback)}; } void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { @@ -489,7 +510,7 @@ void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { return; } StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false); - kAllPullAtomInfo.erase(atomTag); + kAllPullAtomInfo.erase({.atomTag = atomTag}); } } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 4ea1386bf78a..1bd9f92e4448 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -16,15 +16,18 @@ #pragma once +#include <android/os/IPullAtomCallback.h> #include <android/os/IStatsCompanionService.h> #include <android/os/IStatsPullerCallback.h> #include <binder/IServiceManager.h> #include <utils/RefBase.h> #include <utils/threads.h> + #include <list> #include <string> #include <unordered_map> #include <vector> + #include "PullDataReceiver.h" #include "StatsPuller.h" #include "guardrail/StatsdStats.h" @@ -53,6 +56,27 @@ typedef struct { int64_t pullTimeoutNs = StatsdStats::kPullMaxDelayNs; } PullAtomInfo; +typedef struct PullerKey { + // The uid of the process that registers this puller. + const int uid = -1; + // The atom that this puller is for. + const int atomTag; + + bool operator<(const PullerKey& that) const { + if (uid < that.uid) { + return true; + } + if (uid > that.uid) { + return false; + } + return atomTag < that.atomTag; + }; + + bool operator==(const PullerKey& that) const { + return uid == that.uid && atomTag == that.atomTag; + }; +} PullerKey; + class StatsPullerManager : public virtual RefBase { public: StatsPullerManager(); @@ -92,12 +116,16 @@ public: void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService); - void RegisterPullerCallback(int32_t atomTag, - const sp<IStatsPullerCallback>& callback); + // Deprecated, remove after puller API is complete. + void RegisterPullerCallback(int32_t atomTag, const sp<IStatsPullerCallback>& callback); + + void RegisterPullAtomCallback(const int uid, const int32_t atomTag, const int64_t coolDownNs, + const int64_t timeoutNs, const vector<int32_t>& additiveFields, + const sp<IPullAtomCallback>& callback); void UnregisterPullerCallback(int32_t atomTag); - static std::map<int, PullAtomInfo> kAllPullAtomInfo; + static std::map<PullerKey, PullAtomInfo> kAllPullAtomInfo; private: sp<IStatsCompanionService> mStatsCompanionService = nullptr; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index 0b9b6abfd6d6..53fa6301a836 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -55,7 +55,7 @@ using std::vector; */ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap, int tagId) { - if (StatsPullerManager::kAllPullAtomInfo.find(tagId) == + if (StatsPullerManager::kAllPullAtomInfo.find({.atomTag = tagId}) == StatsPullerManager::kAllPullAtomInfo.end()) { VLOG("Unknown pull atom id %d", tagId); return; @@ -121,7 +121,7 @@ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const vector<shared_ptr<LogEvent>> mergedData; const vector<int>& additiveFieldsVec = - StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.additiveFields; + StatsPullerManager::kAllPullAtomInfo.find({.atomTag = tagId})->second.additiveFields; const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end()); bool needMerge = true; diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-greylist-max-q.txt new file mode 100644 index 000000000000..a895a44f4023 --- /dev/null +++ b/config/hiddenapi-greylist-max-q.txt @@ -0,0 +1,703 @@ +Landroid/R$styleable;->ActionBar:[I +Landroid/R$styleable;->ActionBar_background:I +Landroid/R$styleable;->ActionBar_backgroundSplit:I +Landroid/R$styleable;->ActionBar_backgroundStacked:I +Landroid/R$styleable;->ActionBar_divider:I +Landroid/R$styleable;->ActionBar_itemPadding:I +Landroid/R$styleable;->CalendarView:[I +Landroid/R$styleable;->CalendarView_dateTextAppearance:I +Landroid/R$styleable;->CalendarView_firstDayOfWeek:I +Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I +Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I +Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I +Landroid/R$styleable;->CalendarView_shownWeekCount:I +Landroid/R$styleable;->CalendarView_showWeekNumber:I +Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I +Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I +Landroid/R$styleable;->CalendarView_weekNumberColor:I +Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I +Landroid/R$styleable;->CheckBoxPreference:[I +Landroid/R$styleable;->CheckedTextView:[I +Landroid/R$styleable;->CheckedTextView_checkMark:I +Landroid/R$styleable;->CompoundButton:[I +Landroid/R$styleable;->CompoundButton_button:I +Landroid/R$styleable;->ContactsDataKind:[I +Landroid/R$styleable;->DatePicker:[I +Landroid/R$styleable;->DialogPreference:[I +Landroid/R$styleable;->DrawableStates:[I +Landroid/R$styleable;->ExpandableListView:[I +Landroid/R$styleable;->FrameLayout_Layout:[I +Landroid/R$styleable;->HorizontalScrollView:[I +Landroid/R$styleable;->ImageView:[I +Landroid/R$styleable;->ImageView_adjustViewBounds:I +Landroid/R$styleable;->ImageView_baselineAlignBottom:I +Landroid/R$styleable;->ImageView_cropToPadding:I +Landroid/R$styleable;->ImageView_maxHeight:I +Landroid/R$styleable;->ImageView_maxWidth:I +Landroid/R$styleable;->ImageView_scaleType:I +Landroid/R$styleable;->ImageView_src:I +Landroid/R$styleable;->ImageView_tint:I +Landroid/R$styleable;->Keyboard:[I +Landroid/R$styleable;->Keyboard_horizontalGap:I +Landroid/R$styleable;->Keyboard_Key:[I +Landroid/R$styleable;->Keyboard_keyHeight:I +Landroid/R$styleable;->Keyboard_keyWidth:I +Landroid/R$styleable;->Keyboard_Key_codes:I +Landroid/R$styleable;->Keyboard_Key_iconPreview:I +Landroid/R$styleable;->Keyboard_Key_isModifier:I +Landroid/R$styleable;->Keyboard_Key_isRepeatable:I +Landroid/R$styleable;->Keyboard_Key_isSticky:I +Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I +Landroid/R$styleable;->Keyboard_Key_keyIcon:I +Landroid/R$styleable;->Keyboard_Key_keyLabel:I +Landroid/R$styleable;->Keyboard_Key_keyOutputText:I +Landroid/R$styleable;->Keyboard_Key_popupCharacters:I +Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I +Landroid/R$styleable;->Keyboard_Row:[I +Landroid/R$styleable;->Keyboard_Row_keyboardMode:I +Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I +Landroid/R$styleable;->Keyboard_verticalGap:I +Landroid/R$styleable;->LinearLayout:[I +Landroid/R$styleable;->LinearLayout_baselineAligned:I +Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I +Landroid/R$styleable;->LinearLayout_divider:I +Landroid/R$styleable;->LinearLayout_dividerPadding:I +Landroid/R$styleable;->LinearLayout_gravity:I +Landroid/R$styleable;->LinearLayout_Layout:[I +Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I +Landroid/R$styleable;->LinearLayout_Layout_layout_height:I +Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I +Landroid/R$styleable;->LinearLayout_Layout_layout_width:I +Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I +Landroid/R$styleable;->LinearLayout_orientation:I +Landroid/R$styleable;->LinearLayout_showDividers:I +Landroid/R$styleable;->ListView:[I +Landroid/R$styleable;->ListView_divider:I +Landroid/R$styleable;->ListView_dividerHeight:I +Landroid/R$styleable;->LockPatternView:[I +Landroid/R$styleable;->NumberPicker:[I +Landroid/R$styleable;->NumberPicker_solidColor:I +Landroid/R$styleable;->PopupWindow:[I +Landroid/R$styleable;->ProgressBar:[I +Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I +Landroid/R$styleable;->ProgressBar_indeterminateDuration:I +Landroid/R$styleable;->ProgressBar_maxHeight:I +Landroid/R$styleable;->ProgressBar_maxWidth:I +Landroid/R$styleable;->ProgressBar_minHeight:I +Landroid/R$styleable;->ProgressBar_minWidth:I +Landroid/R$styleable;->ProgressBar_progressDrawable:I +Landroid/R$styleable;->RingtonePreference:[I +Landroid/R$styleable;->ScrollView:[I +Landroid/R$styleable;->SearchView:[I +Landroid/R$styleable;->SeekBar:[I +Landroid/R$styleable;->SeekBar_thumb:I +Landroid/R$styleable;->SeekBar_thumbOffset:I +Landroid/R$styleable;->SlidingDrawer:[I +Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I +Landroid/R$styleable;->SlidingDrawer_animateOnClick:I +Landroid/R$styleable;->SlidingDrawer_bottomOffset:I +Landroid/R$styleable;->SlidingDrawer_content:I +Landroid/R$styleable;->SlidingDrawer_handle:I +Landroid/R$styleable;->SlidingDrawer_orientation:I +Landroid/R$styleable;->SlidingDrawer_topOffset:I +Landroid/R$styleable;->Switch:[I +Landroid/R$styleable;->Switch_showText:I +Landroid/R$styleable;->Switch_splitTrack:I +Landroid/R$styleable;->Switch_switchMinWidth:I +Landroid/R$styleable;->Switch_switchPadding:I +Landroid/R$styleable;->Switch_switchTextAppearance:I +Landroid/R$styleable;->Switch_textOff:I +Landroid/R$styleable;->Switch_textOn:I +Landroid/R$styleable;->Switch_thumb:I +Landroid/R$styleable;->Switch_thumbTextPadding:I +Landroid/R$styleable;->Switch_track:I +Landroid/R$styleable;->TextAppearance:[I +Landroid/R$styleable;->TextAppearance_textAllCaps:I +Landroid/R$styleable;->TextAppearance_textColor:I +Landroid/R$styleable;->TextAppearance_textColorHighlight:I +Landroid/R$styleable;->TextAppearance_textColorHint:I +Landroid/R$styleable;->TextAppearance_textColorLink:I +Landroid/R$styleable;->TextAppearance_textSize:I +Landroid/R$styleable;->TextAppearance_textStyle:I +Landroid/R$styleable;->TextAppearance_typeface:I +Landroid/R$styleable;->TextView:[I +Landroid/R$styleable;->TextView_autoLink:I +Landroid/R$styleable;->TextView_autoText:I +Landroid/R$styleable;->TextView_bufferType:I +Landroid/R$styleable;->TextView_capitalize:I +Landroid/R$styleable;->TextView_cursorVisible:I +Landroid/R$styleable;->TextView_digits:I +Landroid/R$styleable;->TextView_drawableBottom:I +Landroid/R$styleable;->TextView_drawableEnd:I +Landroid/R$styleable;->TextView_drawableLeft:I +Landroid/R$styleable;->TextView_drawablePadding:I +Landroid/R$styleable;->TextView_drawableRight:I +Landroid/R$styleable;->TextView_drawableStart:I +Landroid/R$styleable;->TextView_drawableTop:I +Landroid/R$styleable;->TextView_editable:I +Landroid/R$styleable;->TextView_ellipsize:I +Landroid/R$styleable;->TextView_ems:I +Landroid/R$styleable;->TextView_enabled:I +Landroid/R$styleable;->TextView_freezesText:I +Landroid/R$styleable;->TextView_gravity:I +Landroid/R$styleable;->TextView_height:I +Landroid/R$styleable;->TextView_hint:I +Landroid/R$styleable;->TextView_imeActionId:I +Landroid/R$styleable;->TextView_imeActionLabel:I +Landroid/R$styleable;->TextView_imeOptions:I +Landroid/R$styleable;->TextView_includeFontPadding:I +Landroid/R$styleable;->TextView_inputMethod:I +Landroid/R$styleable;->TextView_inputType:I +Landroid/R$styleable;->TextView_lines:I +Landroid/R$styleable;->TextView_lineSpacingExtra:I +Landroid/R$styleable;->TextView_lineSpacingMultiplier:I +Landroid/R$styleable;->TextView_linksClickable:I +Landroid/R$styleable;->TextView_marqueeRepeatLimit:I +Landroid/R$styleable;->TextView_maxEms:I +Landroid/R$styleable;->TextView_maxHeight:I +Landroid/R$styleable;->TextView_maxLength:I +Landroid/R$styleable;->TextView_maxLines:I +Landroid/R$styleable;->TextView_maxWidth:I +Landroid/R$styleable;->TextView_minEms:I +Landroid/R$styleable;->TextView_minHeight:I +Landroid/R$styleable;->TextView_minLines:I +Landroid/R$styleable;->TextView_minWidth:I +Landroid/R$styleable;->TextView_numeric:I +Landroid/R$styleable;->TextView_password:I +Landroid/R$styleable;->TextView_phoneNumber:I +Landroid/R$styleable;->TextView_privateImeOptions:I +Landroid/R$styleable;->TextView_scrollHorizontally:I +Landroid/R$styleable;->TextView_selectAllOnFocus:I +Landroid/R$styleable;->TextView_shadowColor:I +Landroid/R$styleable;->TextView_shadowDx:I +Landroid/R$styleable;->TextView_shadowDy:I +Landroid/R$styleable;->TextView_shadowRadius:I +Landroid/R$styleable;->TextView_singleLine:I +Landroid/R$styleable;->TextView_text:I +Landroid/R$styleable;->TextView_textAllCaps:I +Landroid/R$styleable;->TextView_textAppearance:I +Landroid/R$styleable;->TextView_textColor:I +Landroid/R$styleable;->TextView_textColorHighlight:I +Landroid/R$styleable;->TextView_textColorHint:I +Landroid/R$styleable;->TextView_textColorLink:I +Landroid/R$styleable;->TextView_textCursorDrawable:I +Landroid/R$styleable;->TextView_textIsSelectable:I +Landroid/R$styleable;->TextView_textScaleX:I +Landroid/R$styleable;->TextView_textSelectHandle:I +Landroid/R$styleable;->TextView_textSelectHandleLeft:I +Landroid/R$styleable;->TextView_textSelectHandleRight:I +Landroid/R$styleable;->TextView_textSize:I +Landroid/R$styleable;->TextView_textStyle:I +Landroid/R$styleable;->TextView_typeface:I +Landroid/R$styleable;->TextView_width:I +Landroid/R$styleable;->Theme:[I +Landroid/R$styleable;->View:[I +Landroid/R$styleable;->ViewDrawableStates:[I +Landroid/R$styleable;->ViewGroup_Layout:[I +Landroid/R$styleable;->ViewGroup_Layout_layout_height:I +Landroid/R$styleable;->ViewGroup_Layout_layout_width:I +Landroid/R$styleable;->ViewGroup_MarginLayout:[I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I +Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I +Landroid/R$styleable;->View_alpha:I +Landroid/R$styleable;->View_background:I +Landroid/R$styleable;->View_clickable:I +Landroid/R$styleable;->View_contentDescription:I +Landroid/R$styleable;->View_drawingCacheQuality:I +Landroid/R$styleable;->View_duplicateParentState:I +Landroid/R$styleable;->View_fadingEdge:I +Landroid/R$styleable;->View_filterTouchesWhenObscured:I +Landroid/R$styleable;->View_fitsSystemWindows:I +Landroid/R$styleable;->View_focusable:I +Landroid/R$styleable;->View_focusableInTouchMode:I +Landroid/R$styleable;->View_hapticFeedbackEnabled:I +Landroid/R$styleable;->View_id:I +Landroid/R$styleable;->View_isScrollContainer:I +Landroid/R$styleable;->View_keepScreenOn:I +Landroid/R$styleable;->View_longClickable:I +Landroid/R$styleable;->View_minHeight:I +Landroid/R$styleable;->View_minWidth:I +Landroid/R$styleable;->View_nextFocusDown:I +Landroid/R$styleable;->View_nextFocusLeft:I +Landroid/R$styleable;->View_nextFocusRight:I +Landroid/R$styleable;->View_nextFocusUp:I +Landroid/R$styleable;->View_onClick:I +Landroid/R$styleable;->View_overScrollMode:I +Landroid/R$styleable;->View_padding:I +Landroid/R$styleable;->View_paddingBottom:I +Landroid/R$styleable;->View_paddingEnd:I +Landroid/R$styleable;->View_paddingLeft:I +Landroid/R$styleable;->View_paddingRight:I +Landroid/R$styleable;->View_paddingStart:I +Landroid/R$styleable;->View_paddingTop:I +Landroid/R$styleable;->View_rotation:I +Landroid/R$styleable;->View_rotationX:I +Landroid/R$styleable;->View_rotationY:I +Landroid/R$styleable;->View_saveEnabled:I +Landroid/R$styleable;->View_scaleX:I +Landroid/R$styleable;->View_scaleY:I +Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I +Landroid/R$styleable;->View_scrollbarFadeDuration:I +Landroid/R$styleable;->View_scrollbars:I +Landroid/R$styleable;->View_scrollbarSize:I +Landroid/R$styleable;->View_scrollbarStyle:I +Landroid/R$styleable;->View_scrollbarThumbHorizontal:I +Landroid/R$styleable;->View_scrollbarThumbVertical:I +Landroid/R$styleable;->View_scrollbarTrackHorizontal:I +Landroid/R$styleable;->View_scrollbarTrackVertical:I +Landroid/R$styleable;->View_scrollX:I +Landroid/R$styleable;->View_scrollY:I +Landroid/R$styleable;->View_soundEffectsEnabled:I +Landroid/R$styleable;->View_tag:I +Landroid/R$styleable;->View_transformPivotX:I +Landroid/R$styleable;->View_transformPivotY:I +Landroid/R$styleable;->View_translationX:I +Landroid/R$styleable;->View_translationY:I +Landroid/R$styleable;->View_visibility:I +Landroid/R$styleable;->Window:[I +Landroid/R$styleable;->Window_windowBackground:I +Landroid/R$styleable;->Window_windowFrame:I +Lcom/android/internal/R$anim;->fade_in:I +Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I +Lcom/android/internal/R$array;->config_autoBrightnessLevels:I +Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I +Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I +Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I +Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I +Lcom/android/internal/R$array;->config_tether_upstream_types:I +Lcom/android/internal/R$array;->config_tether_usb_regexs:I +Lcom/android/internal/R$array;->config_tether_wifi_regexs:I +Lcom/android/internal/R$array;->maps_starting_lat_lng:I +Lcom/android/internal/R$array;->maps_starting_zoom:I +Lcom/android/internal/R$attr;->actionBarStyle:I +Lcom/android/internal/R$attr;->buttonStyle:I +Lcom/android/internal/R$attr;->description:I +Lcom/android/internal/R$attr;->editTextStyle:I +Lcom/android/internal/R$attr;->mapViewStyle:I +Lcom/android/internal/R$attr;->popupWindowStyle:I +Lcom/android/internal/R$attr;->state_above_anchor:I +Lcom/android/internal/R$attr;->state_focused:I +Lcom/android/internal/R$attr;->state_pressed:I +Lcom/android/internal/R$attr;->state_selected:I +Lcom/android/internal/R$attr;->switchStyle:I +Lcom/android/internal/R$attr;->text:I +Lcom/android/internal/R$attr;->title:I +Lcom/android/internal/R$attr;->webViewStyle:I +Lcom/android/internal/R$bool;-><init>()V +Lcom/android/internal/R$bool;->config_automatic_brightness_available:I +Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I +Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I +Lcom/android/internal/R$bool;->config_showNavigationBar:I +Lcom/android/internal/R$dimen;-><init>()V +Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I +Lcom/android/internal/R$dimen;->navigation_bar_height:I +Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I +Lcom/android/internal/R$dimen;->navigation_bar_width:I +Lcom/android/internal/R$dimen;->status_bar_height:I +Lcom/android/internal/R$dimen;->toast_y_offset:I +Lcom/android/internal/R$drawable;->btn_check_off:I +Lcom/android/internal/R$drawable;->compass_arrow:I +Lcom/android/internal/R$drawable;->compass_base:I +Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I +Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I +Lcom/android/internal/R$drawable;->loading_tile_android:I +Lcom/android/internal/R$drawable;->maps_google_logo:I +Lcom/android/internal/R$drawable;->no_tile_256:I +Lcom/android/internal/R$drawable;->reticle:I +Lcom/android/internal/R$drawable;->stat_sys_download:I +Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I +Lcom/android/internal/R$id;->account_name:I +Lcom/android/internal/R$id;->account_type:I +Lcom/android/internal/R$id;->alertTitle:I +Lcom/android/internal/R$id;->allow_button:I +Lcom/android/internal/R$id;->amPm:I +Lcom/android/internal/R$id;->authtoken_type:I +Lcom/android/internal/R$id;->background:I +Lcom/android/internal/R$id;->back_button:I +Lcom/android/internal/R$id;->body:I +Lcom/android/internal/R$id;->buttonPanel:I +Lcom/android/internal/R$id;->camera:I +Lcom/android/internal/R$id;->cancel:I +Lcom/android/internal/R$id;->clip_children_set_tag:I +Lcom/android/internal/R$id;->clip_children_tag:I +Lcom/android/internal/R$id;->clip_to_padding_tag:I +Lcom/android/internal/R$id;->closeButton:I +Lcom/android/internal/R$id;->content:I +Lcom/android/internal/R$id;->contentPanel:I +Lcom/android/internal/R$id;->custom:I +Lcom/android/internal/R$id;->customPanel:I +Lcom/android/internal/R$id;->datePicker:I +Lcom/android/internal/R$id;->day:I +Lcom/android/internal/R$id;->deny_button:I +Lcom/android/internal/R$id;->description:I +Lcom/android/internal/R$id;->edit:I +Lcom/android/internal/R$id;->edittext_container:I +Lcom/android/internal/R$id;->find_next:I +Lcom/android/internal/R$id;->find_prev:I +Lcom/android/internal/R$id;->icon:I +Lcom/android/internal/R$id;->keyboard:I +Lcom/android/internal/R$id;->keyboardView:I +Lcom/android/internal/R$id;->line1:I +Lcom/android/internal/R$id;->list_item:I +Lcom/android/internal/R$id;->matches:I +Lcom/android/internal/R$id;->mediacontroller_progress:I +Lcom/android/internal/R$id;->media_actions:I +Lcom/android/internal/R$id;->message:I +Lcom/android/internal/R$id;->minute:I +Lcom/android/internal/R$id;->month:I +Lcom/android/internal/R$id;->notification_header:I +Lcom/android/internal/R$id;->ok:I +Lcom/android/internal/R$id;->overlay:I +Lcom/android/internal/R$id;->packages_list:I +Lcom/android/internal/R$id;->package_label:I +Lcom/android/internal/R$id;->parentPanel:I +Lcom/android/internal/R$id;->pause:I +Lcom/android/internal/R$id;->pending_intent_tag:I +Lcom/android/internal/R$id;->progress:I +Lcom/android/internal/R$id;->redo:I +Lcom/android/internal/R$id;->remote_input_tag:I +Lcom/android/internal/R$id;->right_icon:I +Lcom/android/internal/R$id;->search_src_text:I +Lcom/android/internal/R$id;->share:I +Lcom/android/internal/R$id;->shortcut:I +Lcom/android/internal/R$id;->status_bar_latest_event_content:I +Lcom/android/internal/R$id;->tabcontent:I +Lcom/android/internal/R$id;->tabs:I +Lcom/android/internal/R$id;->text1:I +Lcom/android/internal/R$id;->text2:I +Lcom/android/internal/R$id;->text:I +Lcom/android/internal/R$id;->time:I +Lcom/android/internal/R$id;->timePicker:I +Lcom/android/internal/R$id;->time_current:I +Lcom/android/internal/R$id;->title:I +Lcom/android/internal/R$id;->titleDivider:I +Lcom/android/internal/R$id;->titleDividerTop:I +Lcom/android/internal/R$id;->title_container:I +Lcom/android/internal/R$id;->title_template:I +Lcom/android/internal/R$id;->topPanel:I +Lcom/android/internal/R$id;->up:I +Lcom/android/internal/R$id;->year:I +Lcom/android/internal/R$id;->zoomControls:I +Lcom/android/internal/R$id;->zoomMagnify:I +Lcom/android/internal/R$integer;->config_screenBrightnessDim:I +Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I +Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I +Lcom/android/internal/R$integer;->config_toastDefaultGravity:I +Lcom/android/internal/R$interpolator;->accelerate_cubic:I +Lcom/android/internal/R$interpolator;->decelerate_cubic:I +Lcom/android/internal/R$layout;->notification_template_material_base:I +Lcom/android/internal/R$layout;->preference_header_item:I +Lcom/android/internal/R$layout;->screen_title:I +Lcom/android/internal/R$layout;->select_dialog:I +Lcom/android/internal/R$layout;->select_dialog_multichoice:I +Lcom/android/internal/R$layout;->select_dialog_singlechoice:I +Lcom/android/internal/R$layout;->webview_find:I +Lcom/android/internal/R$layout;->zoom_magnify:I +Lcom/android/internal/R$plurals;->matches_found:I +Lcom/android/internal/R$raw;->loaderror:I +Lcom/android/internal/R$raw;->nodomain:I +Lcom/android/internal/R$string;->byteShort:I +Lcom/android/internal/R$string;->cancel:I +Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I +Lcom/android/internal/R$string;->gigabyteShort:I +Lcom/android/internal/R$string;->kilobyteShort:I +Lcom/android/internal/R$string;->map:I +Lcom/android/internal/R$string;->megabyteShort:I +Lcom/android/internal/R$string;->notification_title:I +Lcom/android/internal/R$string;->no_matches:I +Lcom/android/internal/R$string;->ok:I +Lcom/android/internal/R$string;->petabyteShort:I +Lcom/android/internal/R$string;->redo:I +Lcom/android/internal/R$string;->share:I +Lcom/android/internal/R$string;->terabyteShort:I +Lcom/android/internal/R$string;->whichApplication:I +Lcom/android/internal/R$style;->Animation_DropDownDown:I +Lcom/android/internal/R$style;->Animation_DropDownUp:I +Lcom/android/internal/R$style;->Animation_PopupWindow:I +Lcom/android/internal/R$style;->Theme:I +Lcom/android/internal/R$style;->Theme_Dialog_Alert:I +Lcom/android/internal/R$style;->Theme_Holo_Light:I +Lcom/android/internal/R$style;->Theme_Light:I +Lcom/android/internal/R$styleable;-><init>()V +Lcom/android/internal/R$styleable;->AbsListView:[I +Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I +Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I +Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I +Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I +Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I +Lcom/android/internal/R$styleable;->AbsListView_listSelector:I +Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I +Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I +Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I +Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I +Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I +Lcom/android/internal/R$styleable;->AbsSpinner:[I +Lcom/android/internal/R$styleable;->AccountAuthenticator:[I +Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I +Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I +Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I +Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I +Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I +Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I +Lcom/android/internal/R$styleable;->ActionMode:[I +Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I +Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I +Lcom/android/internal/R$styleable;->AlertDialog:[I +Lcom/android/internal/R$styleable;->AnalogClock:[I +Lcom/android/internal/R$styleable;->AndroidManifest:[I +Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I +Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I +Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I +Lcom/android/internal/R$styleable;->AndroidManifestData:[I +Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I +Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I +Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I +Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I +Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I +Lcom/android/internal/R$styleable;->AndroidManifestService:[I +Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I +Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I +Lcom/android/internal/R$styleable;->AndroidManifestService_name:I +Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I +Lcom/android/internal/R$styleable;->AndroidManifestService_process:I +Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I +Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I +Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I +Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I +Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I +Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I +Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I +Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I +Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I +Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I +Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I +Lcom/android/internal/R$styleable;->CheckBoxPreference:[I +Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I +Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I +Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I +Lcom/android/internal/R$styleable;->CheckedTextView:[I +Lcom/android/internal/R$styleable;->CheckedTextView_checked:I +Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I +Lcom/android/internal/R$styleable;->CompoundButton:[I +Lcom/android/internal/R$styleable;->CompoundButton_button:I +Lcom/android/internal/R$styleable;->CompoundButton_checked:I +Lcom/android/internal/R$styleable;->ContactsDataKind:[I +Lcom/android/internal/R$styleable;->DatePicker:[I +Lcom/android/internal/R$styleable;->DialogPreference:[I +Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I +Lcom/android/internal/R$styleable;->Dream:[I +Lcom/android/internal/R$styleable;->EdgeEffect:[I +Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I +Lcom/android/internal/R$styleable;->FastScroll:[I +Lcom/android/internal/R$styleable;->FrameLayout:[I +Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I +Lcom/android/internal/R$styleable;->Gallery:[I +Lcom/android/internal/R$styleable;->GridView:[I +Lcom/android/internal/R$styleable;->IconMenuView:[I +Lcom/android/internal/R$styleable;->ImageView:[I +Lcom/android/internal/R$styleable;->ImageView_scaleType:I +Lcom/android/internal/R$styleable;->ImageView_src:I +Lcom/android/internal/R$styleable;->Keyboard:[I +Lcom/android/internal/R$styleable;->KeyboardView:[I +Lcom/android/internal/R$styleable;->Keyboard_Key:[I +Lcom/android/internal/R$styleable;->Keyboard_Row:[I +Lcom/android/internal/R$styleable;->ListPreference:[I +Lcom/android/internal/R$styleable;->ListPreference_entries:I +Lcom/android/internal/R$styleable;->ListView:[I +Lcom/android/internal/R$styleable;->ListView_divider:I +Lcom/android/internal/R$styleable;->ListView_dividerHeight:I +Lcom/android/internal/R$styleable;->ListView_entries:I +Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I +Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I +Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I +Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I +Lcom/android/internal/R$styleable;->MapView:[I +Lcom/android/internal/R$styleable;->MapView_apiKey:I +Lcom/android/internal/R$styleable;->MenuGroup:[I +Lcom/android/internal/R$styleable;->MenuItem:[I +Lcom/android/internal/R$styleable;->NumberPicker:[I +Lcom/android/internal/R$styleable;->PopupWindow:[I +Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I +Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I +Lcom/android/internal/R$styleable;->Preference:[I +Lcom/android/internal/R$styleable;->PreferenceGroup:[I +Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I +Lcom/android/internal/R$styleable;->Preference_defaultValue:I +Lcom/android/internal/R$styleable;->Preference_dependency:I +Lcom/android/internal/R$styleable;->Preference_enabled:I +Lcom/android/internal/R$styleable;->Preference_fragment:I +Lcom/android/internal/R$styleable;->Preference_icon:I +Lcom/android/internal/R$styleable;->Preference_key:I +Lcom/android/internal/R$styleable;->Preference_layout:I +Lcom/android/internal/R$styleable;->Preference_order:I +Lcom/android/internal/R$styleable;->Preference_persistent:I +Lcom/android/internal/R$styleable;->Preference_selectable:I +Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I +Lcom/android/internal/R$styleable;->Preference_summary:I +Lcom/android/internal/R$styleable;->Preference_title:I +Lcom/android/internal/R$styleable;->Preference_widgetLayout:I +Lcom/android/internal/R$styleable;->ProgressBar:[I +Lcom/android/internal/R$styleable;->QuickContactBadge:[I +Lcom/android/internal/R$styleable;->RingtonePreference:[I +Lcom/android/internal/R$styleable;->ScrollView:[I +Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I +Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I +Lcom/android/internal/R$styleable;->Switch:[I +Lcom/android/internal/R$styleable;->SwitchPreference:[I +Lcom/android/internal/R$styleable;->SyncAdapter:[I +Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I +Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I +Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I +Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I +Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I +Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I +Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I +Lcom/android/internal/R$styleable;->TabWidget:[I +Lcom/android/internal/R$styleable;->TextAppearance:[I +Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I +Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I +Lcom/android/internal/R$styleable;->TextAppearance_textColor:I +Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I +Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I +Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I +Lcom/android/internal/R$styleable;->TextAppearance_textSize:I +Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I +Lcom/android/internal/R$styleable;->TextAppearance_typeface:I +Lcom/android/internal/R$styleable;->TextClock:[I +Lcom/android/internal/R$styleable;->TextView:[I +Lcom/android/internal/R$styleable;->TextViewAppearance:[I +Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I +Lcom/android/internal/R$styleable;->TextView_autoLink:I +Lcom/android/internal/R$styleable;->TextView_autoText:I +Lcom/android/internal/R$styleable;->TextView_bufferType:I +Lcom/android/internal/R$styleable;->TextView_capitalize:I +Lcom/android/internal/R$styleable;->TextView_cursorVisible:I +Lcom/android/internal/R$styleable;->TextView_digits:I +Lcom/android/internal/R$styleable;->TextView_drawableBottom:I +Lcom/android/internal/R$styleable;->TextView_drawableEnd:I +Lcom/android/internal/R$styleable;->TextView_drawableLeft:I +Lcom/android/internal/R$styleable;->TextView_drawablePadding:I +Lcom/android/internal/R$styleable;->TextView_drawableRight:I +Lcom/android/internal/R$styleable;->TextView_drawableStart:I +Lcom/android/internal/R$styleable;->TextView_drawableTop:I +Lcom/android/internal/R$styleable;->TextView_editable:I +Lcom/android/internal/R$styleable;->TextView_editorExtras:I +Lcom/android/internal/R$styleable;->TextView_ellipsize:I +Lcom/android/internal/R$styleable;->TextView_ems:I +Lcom/android/internal/R$styleable;->TextView_enabled:I +Lcom/android/internal/R$styleable;->TextView_freezesText:I +Lcom/android/internal/R$styleable;->TextView_gravity:I +Lcom/android/internal/R$styleable;->TextView_height:I +Lcom/android/internal/R$styleable;->TextView_hint:I +Lcom/android/internal/R$styleable;->TextView_imeActionId:I +Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I +Lcom/android/internal/R$styleable;->TextView_imeOptions:I +Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I +Lcom/android/internal/R$styleable;->TextView_inputMethod:I +Lcom/android/internal/R$styleable;->TextView_inputType:I +Lcom/android/internal/R$styleable;->TextView_lines:I +Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I +Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I +Lcom/android/internal/R$styleable;->TextView_linksClickable:I +Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I +Lcom/android/internal/R$styleable;->TextView_maxEms:I +Lcom/android/internal/R$styleable;->TextView_maxHeight:I +Lcom/android/internal/R$styleable;->TextView_maxLength:I +Lcom/android/internal/R$styleable;->TextView_maxLines:I +Lcom/android/internal/R$styleable;->TextView_maxWidth:I +Lcom/android/internal/R$styleable;->TextView_minEms:I +Lcom/android/internal/R$styleable;->TextView_minHeight:I +Lcom/android/internal/R$styleable;->TextView_minLines:I +Lcom/android/internal/R$styleable;->TextView_minWidth:I +Lcom/android/internal/R$styleable;->TextView_numeric:I +Lcom/android/internal/R$styleable;->TextView_password:I +Lcom/android/internal/R$styleable;->TextView_phoneNumber:I +Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I +Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I +Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I +Lcom/android/internal/R$styleable;->TextView_shadowColor:I +Lcom/android/internal/R$styleable;->TextView_shadowDx:I +Lcom/android/internal/R$styleable;->TextView_shadowDy:I +Lcom/android/internal/R$styleable;->TextView_shadowRadius:I +Lcom/android/internal/R$styleable;->TextView_singleLine:I +Lcom/android/internal/R$styleable;->TextView_text:I +Lcom/android/internal/R$styleable;->TextView_textAllCaps:I +Lcom/android/internal/R$styleable;->TextView_textAppearance:I +Lcom/android/internal/R$styleable;->TextView_textColor:I +Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I +Lcom/android/internal/R$styleable;->TextView_textColorHint:I +Lcom/android/internal/R$styleable;->TextView_textColorLink:I +Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I +Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I +Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I +Lcom/android/internal/R$styleable;->TextView_textScaleX:I +Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I +Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I +Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I +Lcom/android/internal/R$styleable;->TextView_textSize:I +Lcom/android/internal/R$styleable;->TextView_textStyle:I +Lcom/android/internal/R$styleable;->TextView_typeface:I +Lcom/android/internal/R$styleable;->TextView_width:I +Lcom/android/internal/R$styleable;->Theme:[I +Lcom/android/internal/R$styleable;->TwoLineListItem:[I +Lcom/android/internal/R$styleable;->View:[I +Lcom/android/internal/R$styleable;->ViewAnimator:[I +Lcom/android/internal/R$styleable;->ViewFlipper:[I +Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I +Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I +Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I +Lcom/android/internal/R$styleable;->ViewStub:[I +Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I +Lcom/android/internal/R$styleable;->ViewStub_layout:I +Lcom/android/internal/R$styleable;->View_background:I +Lcom/android/internal/R$styleable;->View_clickable:I +Lcom/android/internal/R$styleable;->View_focusable:I +Lcom/android/internal/R$styleable;->View_id:I +Lcom/android/internal/R$styleable;->View_longClickable:I +Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I +Lcom/android/internal/R$styleable;->Window:[I +Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I +Lcom/android/internal/R$styleable;->Window_windowBackground:I +Lcom/android/internal/R$styleable;->Window_windowFullscreen:I +Lcom/android/internal/R$styleable;->Window_windowIsFloating:I +Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I +Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I +Lcom/android/internal/R$xml;->power_profile:I diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index e5750b9d64b5..a3543dc7f4ee 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -238,270 +238,6 @@ Landroid/os/IVibratorService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os Landroid/os/storage/IObbActionListener$Stub;-><init>()V Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager; -Landroid/R$styleable;->ActionBar:[I -Landroid/R$styleable;->ActionBar_background:I -Landroid/R$styleable;->ActionBar_backgroundSplit:I -Landroid/R$styleable;->ActionBar_backgroundStacked:I -Landroid/R$styleable;->ActionBar_divider:I -Landroid/R$styleable;->ActionBar_itemPadding:I -Landroid/R$styleable;->CalendarView:[I -Landroid/R$styleable;->CalendarView_dateTextAppearance:I -Landroid/R$styleable;->CalendarView_firstDayOfWeek:I -Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I -Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I -Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I -Landroid/R$styleable;->CalendarView_shownWeekCount:I -Landroid/R$styleable;->CalendarView_showWeekNumber:I -Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I -Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I -Landroid/R$styleable;->CalendarView_weekNumberColor:I -Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I -Landroid/R$styleable;->CheckBoxPreference:[I -Landroid/R$styleable;->CheckedTextView:[I -Landroid/R$styleable;->CheckedTextView_checkMark:I -Landroid/R$styleable;->CompoundButton:[I -Landroid/R$styleable;->CompoundButton_button:I -Landroid/R$styleable;->ContactsDataKind:[I -Landroid/R$styleable;->DatePicker:[I -Landroid/R$styleable;->DialogPreference:[I -Landroid/R$styleable;->DrawableStates:[I -Landroid/R$styleable;->ExpandableListView:[I -Landroid/R$styleable;->FrameLayout_Layout:[I -Landroid/R$styleable;->HorizontalScrollView:[I -Landroid/R$styleable;->ImageView:[I -Landroid/R$styleable;->ImageView_adjustViewBounds:I -Landroid/R$styleable;->ImageView_baselineAlignBottom:I -Landroid/R$styleable;->ImageView_cropToPadding:I -Landroid/R$styleable;->ImageView_maxHeight:I -Landroid/R$styleable;->ImageView_maxWidth:I -Landroid/R$styleable;->ImageView_scaleType:I -Landroid/R$styleable;->ImageView_src:I -Landroid/R$styleable;->ImageView_tint:I -Landroid/R$styleable;->Keyboard:[I -Landroid/R$styleable;->Keyboard_horizontalGap:I -Landroid/R$styleable;->Keyboard_Key:[I -Landroid/R$styleable;->Keyboard_keyHeight:I -Landroid/R$styleable;->Keyboard_keyWidth:I -Landroid/R$styleable;->Keyboard_Key_codes:I -Landroid/R$styleable;->Keyboard_Key_iconPreview:I -Landroid/R$styleable;->Keyboard_Key_isModifier:I -Landroid/R$styleable;->Keyboard_Key_isRepeatable:I -Landroid/R$styleable;->Keyboard_Key_isSticky:I -Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I -Landroid/R$styleable;->Keyboard_Key_keyIcon:I -Landroid/R$styleable;->Keyboard_Key_keyLabel:I -Landroid/R$styleable;->Keyboard_Key_keyOutputText:I -Landroid/R$styleable;->Keyboard_Key_popupCharacters:I -Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I -Landroid/R$styleable;->Keyboard_Row:[I -Landroid/R$styleable;->Keyboard_Row_keyboardMode:I -Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I -Landroid/R$styleable;->Keyboard_verticalGap:I -Landroid/R$styleable;->LinearLayout:[I -Landroid/R$styleable;->LinearLayout_baselineAligned:I -Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I -Landroid/R$styleable;->LinearLayout_divider:I -Landroid/R$styleable;->LinearLayout_dividerPadding:I -Landroid/R$styleable;->LinearLayout_gravity:I -Landroid/R$styleable;->LinearLayout_Layout:[I -Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I -Landroid/R$styleable;->LinearLayout_Layout_layout_height:I -Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I -Landroid/R$styleable;->LinearLayout_Layout_layout_width:I -Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I -Landroid/R$styleable;->LinearLayout_orientation:I -Landroid/R$styleable;->LinearLayout_showDividers:I -Landroid/R$styleable;->ListView:[I -Landroid/R$styleable;->ListView_divider:I -Landroid/R$styleable;->ListView_dividerHeight:I -Landroid/R$styleable;->LockPatternView:[I -Landroid/R$styleable;->NumberPicker:[I -Landroid/R$styleable;->NumberPicker_solidColor:I -Landroid/R$styleable;->PopupWindow:[I -Landroid/R$styleable;->ProgressBar:[I -Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I -Landroid/R$styleable;->ProgressBar_indeterminateDuration:I -Landroid/R$styleable;->ProgressBar_maxHeight:I -Landroid/R$styleable;->ProgressBar_maxWidth:I -Landroid/R$styleable;->ProgressBar_minHeight:I -Landroid/R$styleable;->ProgressBar_minWidth:I -Landroid/R$styleable;->ProgressBar_progressDrawable:I -Landroid/R$styleable;->RingtonePreference:[I -Landroid/R$styleable;->ScrollView:[I -Landroid/R$styleable;->SearchView:[I -Landroid/R$styleable;->SeekBar:[I -Landroid/R$styleable;->SeekBar_thumb:I -Landroid/R$styleable;->SeekBar_thumbOffset:I -Landroid/R$styleable;->SlidingDrawer:[I -Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I -Landroid/R$styleable;->SlidingDrawer_animateOnClick:I -Landroid/R$styleable;->SlidingDrawer_bottomOffset:I -Landroid/R$styleable;->SlidingDrawer_content:I -Landroid/R$styleable;->SlidingDrawer_handle:I -Landroid/R$styleable;->SlidingDrawer_orientation:I -Landroid/R$styleable;->SlidingDrawer_topOffset:I -Landroid/R$styleable;->Switch:[I -Landroid/R$styleable;->Switch_showText:I -Landroid/R$styleable;->Switch_splitTrack:I -Landroid/R$styleable;->Switch_switchMinWidth:I -Landroid/R$styleable;->Switch_switchPadding:I -Landroid/R$styleable;->Switch_switchTextAppearance:I -Landroid/R$styleable;->Switch_textOff:I -Landroid/R$styleable;->Switch_textOn:I -Landroid/R$styleable;->Switch_thumb:I -Landroid/R$styleable;->Switch_thumbTextPadding:I -Landroid/R$styleable;->Switch_track:I -Landroid/R$styleable;->TextAppearance:[I -Landroid/R$styleable;->TextAppearance_textAllCaps:I -Landroid/R$styleable;->TextAppearance_textColor:I -Landroid/R$styleable;->TextAppearance_textColorHighlight:I -Landroid/R$styleable;->TextAppearance_textColorHint:I -Landroid/R$styleable;->TextAppearance_textColorLink:I -Landroid/R$styleable;->TextAppearance_textSize:I -Landroid/R$styleable;->TextAppearance_textStyle:I -Landroid/R$styleable;->TextAppearance_typeface:I -Landroid/R$styleable;->TextView:[I -Landroid/R$styleable;->TextView_autoLink:I -Landroid/R$styleable;->TextView_autoText:I -Landroid/R$styleable;->TextView_bufferType:I -Landroid/R$styleable;->TextView_capitalize:I -Landroid/R$styleable;->TextView_cursorVisible:I -Landroid/R$styleable;->TextView_digits:I -Landroid/R$styleable;->TextView_drawableBottom:I -Landroid/R$styleable;->TextView_drawableEnd:I -Landroid/R$styleable;->TextView_drawableLeft:I -Landroid/R$styleable;->TextView_drawablePadding:I -Landroid/R$styleable;->TextView_drawableRight:I -Landroid/R$styleable;->TextView_drawableStart:I -Landroid/R$styleable;->TextView_drawableTop:I -Landroid/R$styleable;->TextView_editable:I -Landroid/R$styleable;->TextView_ellipsize:I -Landroid/R$styleable;->TextView_ems:I -Landroid/R$styleable;->TextView_enabled:I -Landroid/R$styleable;->TextView_freezesText:I -Landroid/R$styleable;->TextView_gravity:I -Landroid/R$styleable;->TextView_height:I -Landroid/R$styleable;->TextView_hint:I -Landroid/R$styleable;->TextView_imeActionId:I -Landroid/R$styleable;->TextView_imeActionLabel:I -Landroid/R$styleable;->TextView_imeOptions:I -Landroid/R$styleable;->TextView_includeFontPadding:I -Landroid/R$styleable;->TextView_inputMethod:I -Landroid/R$styleable;->TextView_inputType:I -Landroid/R$styleable;->TextView_lines:I -Landroid/R$styleable;->TextView_lineSpacingExtra:I -Landroid/R$styleable;->TextView_lineSpacingMultiplier:I -Landroid/R$styleable;->TextView_linksClickable:I -Landroid/R$styleable;->TextView_marqueeRepeatLimit:I -Landroid/R$styleable;->TextView_maxEms:I -Landroid/R$styleable;->TextView_maxHeight:I -Landroid/R$styleable;->TextView_maxLength:I -Landroid/R$styleable;->TextView_maxLines:I -Landroid/R$styleable;->TextView_maxWidth:I -Landroid/R$styleable;->TextView_minEms:I -Landroid/R$styleable;->TextView_minHeight:I -Landroid/R$styleable;->TextView_minLines:I -Landroid/R$styleable;->TextView_minWidth:I -Landroid/R$styleable;->TextView_numeric:I -Landroid/R$styleable;->TextView_password:I -Landroid/R$styleable;->TextView_phoneNumber:I -Landroid/R$styleable;->TextView_privateImeOptions:I -Landroid/R$styleable;->TextView_scrollHorizontally:I -Landroid/R$styleable;->TextView_selectAllOnFocus:I -Landroid/R$styleable;->TextView_shadowColor:I -Landroid/R$styleable;->TextView_shadowDx:I -Landroid/R$styleable;->TextView_shadowDy:I -Landroid/R$styleable;->TextView_shadowRadius:I -Landroid/R$styleable;->TextView_singleLine:I -Landroid/R$styleable;->TextView_text:I -Landroid/R$styleable;->TextView_textAllCaps:I -Landroid/R$styleable;->TextView_textAppearance:I -Landroid/R$styleable;->TextView_textColor:I -Landroid/R$styleable;->TextView_textColorHighlight:I -Landroid/R$styleable;->TextView_textColorHint:I -Landroid/R$styleable;->TextView_textColorLink:I -Landroid/R$styleable;->TextView_textCursorDrawable:I -Landroid/R$styleable;->TextView_textIsSelectable:I -Landroid/R$styleable;->TextView_textScaleX:I -Landroid/R$styleable;->TextView_textSelectHandle:I -Landroid/R$styleable;->TextView_textSelectHandleLeft:I -Landroid/R$styleable;->TextView_textSelectHandleRight:I -Landroid/R$styleable;->TextView_textSize:I -Landroid/R$styleable;->TextView_textStyle:I -Landroid/R$styleable;->TextView_typeface:I -Landroid/R$styleable;->TextView_width:I -Landroid/R$styleable;->Theme:[I -Landroid/R$styleable;->View:[I -Landroid/R$styleable;->ViewDrawableStates:[I -Landroid/R$styleable;->ViewGroup_Layout:[I -Landroid/R$styleable;->ViewGroup_Layout_layout_height:I -Landroid/R$styleable;->ViewGroup_Layout_layout_width:I -Landroid/R$styleable;->ViewGroup_MarginLayout:[I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I -Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I -Landroid/R$styleable;->View_alpha:I -Landroid/R$styleable;->View_background:I -Landroid/R$styleable;->View_clickable:I -Landroid/R$styleable;->View_contentDescription:I -Landroid/R$styleable;->View_drawingCacheQuality:I -Landroid/R$styleable;->View_duplicateParentState:I -Landroid/R$styleable;->View_fadingEdge:I -Landroid/R$styleable;->View_filterTouchesWhenObscured:I -Landroid/R$styleable;->View_fitsSystemWindows:I -Landroid/R$styleable;->View_focusable:I -Landroid/R$styleable;->View_focusableInTouchMode:I -Landroid/R$styleable;->View_hapticFeedbackEnabled:I -Landroid/R$styleable;->View_id:I -Landroid/R$styleable;->View_isScrollContainer:I -Landroid/R$styleable;->View_keepScreenOn:I -Landroid/R$styleable;->View_longClickable:I -Landroid/R$styleable;->View_minHeight:I -Landroid/R$styleable;->View_minWidth:I -Landroid/R$styleable;->View_nextFocusDown:I -Landroid/R$styleable;->View_nextFocusLeft:I -Landroid/R$styleable;->View_nextFocusRight:I -Landroid/R$styleable;->View_nextFocusUp:I -Landroid/R$styleable;->View_onClick:I -Landroid/R$styleable;->View_overScrollMode:I -Landroid/R$styleable;->View_padding:I -Landroid/R$styleable;->View_paddingBottom:I -Landroid/R$styleable;->View_paddingEnd:I -Landroid/R$styleable;->View_paddingLeft:I -Landroid/R$styleable;->View_paddingRight:I -Landroid/R$styleable;->View_paddingStart:I -Landroid/R$styleable;->View_paddingTop:I -Landroid/R$styleable;->View_rotation:I -Landroid/R$styleable;->View_rotationX:I -Landroid/R$styleable;->View_rotationY:I -Landroid/R$styleable;->View_saveEnabled:I -Landroid/R$styleable;->View_scaleX:I -Landroid/R$styleable;->View_scaleY:I -Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I -Landroid/R$styleable;->View_scrollbarFadeDuration:I -Landroid/R$styleable;->View_scrollbars:I -Landroid/R$styleable;->View_scrollbarSize:I -Landroid/R$styleable;->View_scrollbarStyle:I -Landroid/R$styleable;->View_scrollbarThumbHorizontal:I -Landroid/R$styleable;->View_scrollbarThumbVertical:I -Landroid/R$styleable;->View_scrollbarTrackHorizontal:I -Landroid/R$styleable;->View_scrollbarTrackVertical:I -Landroid/R$styleable;->View_scrollX:I -Landroid/R$styleable;->View_scrollY:I -Landroid/R$styleable;->View_soundEffectsEnabled:I -Landroid/R$styleable;->View_tag:I -Landroid/R$styleable;->View_transformPivotX:I -Landroid/R$styleable;->View_transformPivotY:I -Landroid/R$styleable;->View_translationX:I -Landroid/R$styleable;->View_translationY:I -Landroid/R$styleable;->View_visibility:I -Landroid/R$styleable;->Window:[I -Landroid/R$styleable;->Window_windowBackground:I -Landroid/R$styleable;->Window_windowFrame:I Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService; Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService; Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager; @@ -589,445 +325,6 @@ Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landr Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService; Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService; Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback; -Lcom/android/internal/R$anim;->fade_in:I -Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I -Lcom/android/internal/R$array;->config_autoBrightnessLevels:I -Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I -Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I -Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I -Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I -Lcom/android/internal/R$array;->config_tether_upstream_types:I -Lcom/android/internal/R$array;->config_tether_usb_regexs:I -Lcom/android/internal/R$array;->config_tether_wifi_regexs:I -Lcom/android/internal/R$array;->maps_starting_lat_lng:I -Lcom/android/internal/R$array;->maps_starting_zoom:I -Lcom/android/internal/R$attr;->actionBarStyle:I -Lcom/android/internal/R$attr;->buttonStyle:I -Lcom/android/internal/R$attr;->description:I -Lcom/android/internal/R$attr;->editTextStyle:I -Lcom/android/internal/R$attr;->mapViewStyle:I -Lcom/android/internal/R$attr;->popupWindowStyle:I -Lcom/android/internal/R$attr;->state_above_anchor:I -Lcom/android/internal/R$attr;->state_focused:I -Lcom/android/internal/R$attr;->state_pressed:I -Lcom/android/internal/R$attr;->state_selected:I -Lcom/android/internal/R$attr;->switchStyle:I -Lcom/android/internal/R$attr;->text:I -Lcom/android/internal/R$attr;->title:I -Lcom/android/internal/R$attr;->webViewStyle:I -Lcom/android/internal/R$bool;-><init>()V -Lcom/android/internal/R$bool;->config_automatic_brightness_available:I -Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I -Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I -Lcom/android/internal/R$bool;->config_showNavigationBar:I -Lcom/android/internal/R$dimen;-><init>()V -Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I -Lcom/android/internal/R$dimen;->navigation_bar_height:I -Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I -Lcom/android/internal/R$dimen;->navigation_bar_width:I -Lcom/android/internal/R$dimen;->status_bar_height:I -Lcom/android/internal/R$dimen;->toast_y_offset:I -Lcom/android/internal/R$drawable;->btn_check_off:I -Lcom/android/internal/R$drawable;->compass_arrow:I -Lcom/android/internal/R$drawable;->compass_base:I -Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I -Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I -Lcom/android/internal/R$drawable;->loading_tile_android:I -Lcom/android/internal/R$drawable;->maps_google_logo:I -Lcom/android/internal/R$drawable;->no_tile_256:I -Lcom/android/internal/R$drawable;->reticle:I -Lcom/android/internal/R$drawable;->stat_sys_download:I -Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I -Lcom/android/internal/R$id;->account_name:I -Lcom/android/internal/R$id;->account_type:I -Lcom/android/internal/R$id;->alertTitle:I -Lcom/android/internal/R$id;->allow_button:I -Lcom/android/internal/R$id;->amPm:I -Lcom/android/internal/R$id;->authtoken_type:I -Lcom/android/internal/R$id;->background:I -Lcom/android/internal/R$id;->back_button:I -Lcom/android/internal/R$id;->body:I -Lcom/android/internal/R$id;->buttonPanel:I -Lcom/android/internal/R$id;->camera:I -Lcom/android/internal/R$id;->cancel:I -Lcom/android/internal/R$id;->clip_children_set_tag:I -Lcom/android/internal/R$id;->clip_children_tag:I -Lcom/android/internal/R$id;->clip_to_padding_tag:I -Lcom/android/internal/R$id;->closeButton:I -Lcom/android/internal/R$id;->content:I -Lcom/android/internal/R$id;->contentPanel:I -Lcom/android/internal/R$id;->custom:I -Lcom/android/internal/R$id;->customPanel:I -Lcom/android/internal/R$id;->datePicker:I -Lcom/android/internal/R$id;->day:I -Lcom/android/internal/R$id;->deny_button:I -Lcom/android/internal/R$id;->description:I -Lcom/android/internal/R$id;->edit:I -Lcom/android/internal/R$id;->edittext_container:I -Lcom/android/internal/R$id;->find_next:I -Lcom/android/internal/R$id;->find_prev:I -Lcom/android/internal/R$id;->icon:I -Lcom/android/internal/R$id;->keyboard:I -Lcom/android/internal/R$id;->keyboardView:I -Lcom/android/internal/R$id;->line1:I -Lcom/android/internal/R$id;->list_item:I -Lcom/android/internal/R$id;->matches:I -Lcom/android/internal/R$id;->mediacontroller_progress:I -Lcom/android/internal/R$id;->media_actions:I -Lcom/android/internal/R$id;->message:I -Lcom/android/internal/R$id;->minute:I -Lcom/android/internal/R$id;->month:I -Lcom/android/internal/R$id;->notification_header:I -Lcom/android/internal/R$id;->ok:I -Lcom/android/internal/R$id;->overlay:I -Lcom/android/internal/R$id;->packages_list:I -Lcom/android/internal/R$id;->package_label:I -Lcom/android/internal/R$id;->parentPanel:I -Lcom/android/internal/R$id;->pause:I -Lcom/android/internal/R$id;->pending_intent_tag:I -Lcom/android/internal/R$id;->progress:I -Lcom/android/internal/R$id;->redo:I -Lcom/android/internal/R$id;->remote_input_tag:I -Lcom/android/internal/R$id;->right_icon:I -Lcom/android/internal/R$id;->search_src_text:I -Lcom/android/internal/R$id;->share:I -Lcom/android/internal/R$id;->shortcut:I -Lcom/android/internal/R$id;->status_bar_latest_event_content:I -Lcom/android/internal/R$id;->tabcontent:I -Lcom/android/internal/R$id;->tabs:I -Lcom/android/internal/R$id;->text1:I -Lcom/android/internal/R$id;->text2:I -Lcom/android/internal/R$id;->text:I -Lcom/android/internal/R$id;->time:I -Lcom/android/internal/R$id;->timePicker:I -Lcom/android/internal/R$id;->time_current:I -Lcom/android/internal/R$id;->title:I -Lcom/android/internal/R$id;->titleDivider:I -Lcom/android/internal/R$id;->titleDividerTop:I -Lcom/android/internal/R$id;->title_container:I -Lcom/android/internal/R$id;->title_template:I -Lcom/android/internal/R$id;->topPanel:I -Lcom/android/internal/R$id;->up:I -Lcom/android/internal/R$id;->year:I -Lcom/android/internal/R$id;->zoomControls:I -Lcom/android/internal/R$id;->zoomMagnify:I -Lcom/android/internal/R$integer;->config_screenBrightnessDim:I -Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I -Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I -Lcom/android/internal/R$integer;->config_toastDefaultGravity:I -Lcom/android/internal/R$interpolator;->accelerate_cubic:I -Lcom/android/internal/R$interpolator;->decelerate_cubic:I -Lcom/android/internal/R$layout;->notification_template_material_base:I -Lcom/android/internal/R$layout;->preference_header_item:I -Lcom/android/internal/R$layout;->screen_title:I -Lcom/android/internal/R$layout;->select_dialog:I -Lcom/android/internal/R$layout;->select_dialog_multichoice:I -Lcom/android/internal/R$layout;->select_dialog_singlechoice:I -Lcom/android/internal/R$layout;->webview_find:I -Lcom/android/internal/R$layout;->zoom_magnify:I -Lcom/android/internal/R$plurals;->matches_found:I -Lcom/android/internal/R$raw;->loaderror:I -Lcom/android/internal/R$raw;->nodomain:I -Lcom/android/internal/R$string;->byteShort:I -Lcom/android/internal/R$string;->cancel:I -Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I -Lcom/android/internal/R$string;->gigabyteShort:I -Lcom/android/internal/R$string;->kilobyteShort:I -Lcom/android/internal/R$string;->map:I -Lcom/android/internal/R$string;->megabyteShort:I -Lcom/android/internal/R$string;->notification_title:I -Lcom/android/internal/R$string;->no_matches:I -Lcom/android/internal/R$string;->ok:I -Lcom/android/internal/R$string;->petabyteShort:I -Lcom/android/internal/R$string;->redo:I -Lcom/android/internal/R$string;->share:I -Lcom/android/internal/R$string;->terabyteShort:I -Lcom/android/internal/R$string;->whichApplication:I -Lcom/android/internal/R$style;->Animation_DropDownDown:I -Lcom/android/internal/R$style;->Animation_DropDownUp:I -Lcom/android/internal/R$style;->Animation_PopupWindow:I -Lcom/android/internal/R$style;->Theme:I -Lcom/android/internal/R$style;->Theme_Dialog_Alert:I -Lcom/android/internal/R$style;->Theme_Holo_Light:I -Lcom/android/internal/R$style;->Theme_Light:I -Lcom/android/internal/R$styleable;-><init>()V -Lcom/android/internal/R$styleable;->AbsListView:[I -Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I -Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I -Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I -Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I -Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I -Lcom/android/internal/R$styleable;->AbsListView_listSelector:I -Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I -Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I -Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I -Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I -Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I -Lcom/android/internal/R$styleable;->AbsSpinner:[I -Lcom/android/internal/R$styleable;->AccountAuthenticator:[I -Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I -Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I -Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I -Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I -Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I -Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I -Lcom/android/internal/R$styleable;->ActionMode:[I -Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I -Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I -Lcom/android/internal/R$styleable;->AlertDialog:[I -Lcom/android/internal/R$styleable;->AnalogClock:[I -Lcom/android/internal/R$styleable;->AndroidManifest:[I -Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I -Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I -Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I -Lcom/android/internal/R$styleable;->AndroidManifestData:[I -Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I -Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I -Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I -Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I -Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I -Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I -Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I -Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I -Lcom/android/internal/R$styleable;->AndroidManifestService:[I -Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I -Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I -Lcom/android/internal/R$styleable;->AndroidManifestService_name:I -Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I -Lcom/android/internal/R$styleable;->AndroidManifestService_process:I -Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I -Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I -Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I -Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I -Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I -Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I -Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I -Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I -Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I -Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I -Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I -Lcom/android/internal/R$styleable;->CheckBoxPreference:[I -Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I -Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I -Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I -Lcom/android/internal/R$styleable;->CheckedTextView:[I -Lcom/android/internal/R$styleable;->CheckedTextView_checked:I -Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I -Lcom/android/internal/R$styleable;->CompoundButton:[I -Lcom/android/internal/R$styleable;->CompoundButton_button:I -Lcom/android/internal/R$styleable;->CompoundButton_checked:I -Lcom/android/internal/R$styleable;->ContactsDataKind:[I -Lcom/android/internal/R$styleable;->DatePicker:[I -Lcom/android/internal/R$styleable;->DialogPreference:[I -Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I -Lcom/android/internal/R$styleable;->Dream:[I -Lcom/android/internal/R$styleable;->EdgeEffect:[I -Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I -Lcom/android/internal/R$styleable;->FastScroll:[I -Lcom/android/internal/R$styleable;->FrameLayout:[I -Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I -Lcom/android/internal/R$styleable;->Gallery:[I -Lcom/android/internal/R$styleable;->GridView:[I -Lcom/android/internal/R$styleable;->IconMenuView:[I -Lcom/android/internal/R$styleable;->ImageView:[I -Lcom/android/internal/R$styleable;->ImageView_scaleType:I -Lcom/android/internal/R$styleable;->ImageView_src:I -Lcom/android/internal/R$styleable;->Keyboard:[I -Lcom/android/internal/R$styleable;->KeyboardView:[I -Lcom/android/internal/R$styleable;->Keyboard_Key:[I -Lcom/android/internal/R$styleable;->Keyboard_Row:[I -Lcom/android/internal/R$styleable;->ListPreference:[I -Lcom/android/internal/R$styleable;->ListPreference_entries:I -Lcom/android/internal/R$styleable;->ListView:[I -Lcom/android/internal/R$styleable;->ListView_divider:I -Lcom/android/internal/R$styleable;->ListView_dividerHeight:I -Lcom/android/internal/R$styleable;->ListView_entries:I -Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I -Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I -Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I -Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I -Lcom/android/internal/R$styleable;->MapView:[I -Lcom/android/internal/R$styleable;->MapView_apiKey:I -Lcom/android/internal/R$styleable;->MenuGroup:[I -Lcom/android/internal/R$styleable;->MenuItem:[I -Lcom/android/internal/R$styleable;->NumberPicker:[I -Lcom/android/internal/R$styleable;->PopupWindow:[I -Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I -Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I -Lcom/android/internal/R$styleable;->Preference:[I -Lcom/android/internal/R$styleable;->PreferenceGroup:[I -Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I -Lcom/android/internal/R$styleable;->Preference_defaultValue:I -Lcom/android/internal/R$styleable;->Preference_dependency:I -Lcom/android/internal/R$styleable;->Preference_enabled:I -Lcom/android/internal/R$styleable;->Preference_fragment:I -Lcom/android/internal/R$styleable;->Preference_icon:I -Lcom/android/internal/R$styleable;->Preference_key:I -Lcom/android/internal/R$styleable;->Preference_layout:I -Lcom/android/internal/R$styleable;->Preference_order:I -Lcom/android/internal/R$styleable;->Preference_persistent:I -Lcom/android/internal/R$styleable;->Preference_selectable:I -Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I -Lcom/android/internal/R$styleable;->Preference_summary:I -Lcom/android/internal/R$styleable;->Preference_title:I -Lcom/android/internal/R$styleable;->Preference_widgetLayout:I -Lcom/android/internal/R$styleable;->ProgressBar:[I -Lcom/android/internal/R$styleable;->QuickContactBadge:[I -Lcom/android/internal/R$styleable;->RingtonePreference:[I -Lcom/android/internal/R$styleable;->ScrollView:[I -Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I -Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I -Lcom/android/internal/R$styleable;->Switch:[I -Lcom/android/internal/R$styleable;->SwitchPreference:[I -Lcom/android/internal/R$styleable;->SyncAdapter:[I -Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I -Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I -Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I -Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I -Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I -Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I -Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I -Lcom/android/internal/R$styleable;->TabWidget:[I -Lcom/android/internal/R$styleable;->TextAppearance:[I -Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I -Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I -Lcom/android/internal/R$styleable;->TextAppearance_textColor:I -Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I -Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I -Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I -Lcom/android/internal/R$styleable;->TextAppearance_textSize:I -Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I -Lcom/android/internal/R$styleable;->TextAppearance_typeface:I -Lcom/android/internal/R$styleable;->TextClock:[I -Lcom/android/internal/R$styleable;->TextView:[I -Lcom/android/internal/R$styleable;->TextViewAppearance:[I -Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I -Lcom/android/internal/R$styleable;->TextView_autoLink:I -Lcom/android/internal/R$styleable;->TextView_autoText:I -Lcom/android/internal/R$styleable;->TextView_bufferType:I -Lcom/android/internal/R$styleable;->TextView_capitalize:I -Lcom/android/internal/R$styleable;->TextView_cursorVisible:I -Lcom/android/internal/R$styleable;->TextView_digits:I -Lcom/android/internal/R$styleable;->TextView_drawableBottom:I -Lcom/android/internal/R$styleable;->TextView_drawableEnd:I -Lcom/android/internal/R$styleable;->TextView_drawableLeft:I -Lcom/android/internal/R$styleable;->TextView_drawablePadding:I -Lcom/android/internal/R$styleable;->TextView_drawableRight:I -Lcom/android/internal/R$styleable;->TextView_drawableStart:I -Lcom/android/internal/R$styleable;->TextView_drawableTop:I -Lcom/android/internal/R$styleable;->TextView_editable:I -Lcom/android/internal/R$styleable;->TextView_editorExtras:I -Lcom/android/internal/R$styleable;->TextView_ellipsize:I -Lcom/android/internal/R$styleable;->TextView_ems:I -Lcom/android/internal/R$styleable;->TextView_enabled:I -Lcom/android/internal/R$styleable;->TextView_freezesText:I -Lcom/android/internal/R$styleable;->TextView_gravity:I -Lcom/android/internal/R$styleable;->TextView_height:I -Lcom/android/internal/R$styleable;->TextView_hint:I -Lcom/android/internal/R$styleable;->TextView_imeActionId:I -Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I -Lcom/android/internal/R$styleable;->TextView_imeOptions:I -Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I -Lcom/android/internal/R$styleable;->TextView_inputMethod:I -Lcom/android/internal/R$styleable;->TextView_inputType:I -Lcom/android/internal/R$styleable;->TextView_lines:I -Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I -Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I -Lcom/android/internal/R$styleable;->TextView_linksClickable:I -Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I -Lcom/android/internal/R$styleable;->TextView_maxEms:I -Lcom/android/internal/R$styleable;->TextView_maxHeight:I -Lcom/android/internal/R$styleable;->TextView_maxLength:I -Lcom/android/internal/R$styleable;->TextView_maxLines:I -Lcom/android/internal/R$styleable;->TextView_maxWidth:I -Lcom/android/internal/R$styleable;->TextView_minEms:I -Lcom/android/internal/R$styleable;->TextView_minHeight:I -Lcom/android/internal/R$styleable;->TextView_minLines:I -Lcom/android/internal/R$styleable;->TextView_minWidth:I -Lcom/android/internal/R$styleable;->TextView_numeric:I -Lcom/android/internal/R$styleable;->TextView_password:I -Lcom/android/internal/R$styleable;->TextView_phoneNumber:I -Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I -Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I -Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I -Lcom/android/internal/R$styleable;->TextView_shadowColor:I -Lcom/android/internal/R$styleable;->TextView_shadowDx:I -Lcom/android/internal/R$styleable;->TextView_shadowDy:I -Lcom/android/internal/R$styleable;->TextView_shadowRadius:I -Lcom/android/internal/R$styleable;->TextView_singleLine:I -Lcom/android/internal/R$styleable;->TextView_text:I -Lcom/android/internal/R$styleable;->TextView_textAllCaps:I -Lcom/android/internal/R$styleable;->TextView_textAppearance:I -Lcom/android/internal/R$styleable;->TextView_textColor:I -Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I -Lcom/android/internal/R$styleable;->TextView_textColorHint:I -Lcom/android/internal/R$styleable;->TextView_textColorLink:I -Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I -Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I -Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I -Lcom/android/internal/R$styleable;->TextView_textScaleX:I -Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I -Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I -Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I -Lcom/android/internal/R$styleable;->TextView_textSize:I -Lcom/android/internal/R$styleable;->TextView_textStyle:I -Lcom/android/internal/R$styleable;->TextView_typeface:I -Lcom/android/internal/R$styleable;->TextView_width:I -Lcom/android/internal/R$styleable;->Theme:[I -Lcom/android/internal/R$styleable;->TwoLineListItem:[I -Lcom/android/internal/R$styleable;->View:[I -Lcom/android/internal/R$styleable;->ViewAnimator:[I -Lcom/android/internal/R$styleable;->ViewFlipper:[I -Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I -Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I -Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I -Lcom/android/internal/R$styleable;->ViewStub:[I -Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I -Lcom/android/internal/R$styleable;->ViewStub_layout:I -Lcom/android/internal/R$styleable;->View_background:I -Lcom/android/internal/R$styleable;->View_clickable:I -Lcom/android/internal/R$styleable;->View_focusable:I -Lcom/android/internal/R$styleable;->View_id:I -Lcom/android/internal/R$styleable;->View_longClickable:I -Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I -Lcom/android/internal/R$styleable;->Window:[I -Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I -Lcom/android/internal/R$styleable;->Window_windowBackground:I -Lcom/android/internal/R$styleable;->Window_windowFullscreen:I -Lcom/android/internal/R$styleable;->Window_windowIsFloating:I -Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I -Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I -Lcom/android/internal/R$xml;->power_profile:I Lcom/android/internal/statusbar/IStatusBar$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBar; Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index e738b19f420a..61c5dac03da6 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -22,6 +22,8 @@ import android.accessibilityservice.AccessibilityButtonController.AccessibilityB import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -32,8 +34,10 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.hardware.fingerprint.FingerprintManager; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; import android.util.AttributeSet; import android.util.SparseArray; import android.util.TypedValue; @@ -43,6 +47,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; +import com.android.internal.compat.IPlatformCompat; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -299,6 +304,11 @@ public class AccessibilityServiceInfo implements Parcelable { /** * This flag indicates to the system that the accessibility service requests that an * accessibility button be shown within the system's navigation area, if available. + * <p> + * <strong>Note:</strong> For accessibility services targeting APIs greater than + * {@link Build.VERSION_CODES#Q API 29}, this flag must be specified in the + * accessibility service metadata file. Otherwise, it will be ignored. + * </p> */ public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100; @@ -422,6 +432,12 @@ public class AccessibilityServiceInfo implements Parcelable { * <p> * <strong>Can be dynamically set at runtime.</strong> * </p> + * <p> + * <strong>Note:</strong> Accessibility services with targetSdkVersion greater than + * {@link Build.VERSION_CODES#Q API 29} cannot dynamically set the + * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} at runtime. It must be specified in the + * accessibility service metadata file. + * </p> * @see #DEFAULT * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE @@ -497,6 +513,15 @@ public class AccessibilityServiceInfo implements Parcelable { private String mNonLocalizedDescription; /** + * For accessibility services targeting APIs greater than {@link Build.VERSION_CODES#Q API 29}, + * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} must be specified in the accessibility service + * metadata file. Otherwise, it will be ignored. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) + private static final long REQUEST_ACCESSIBILITY_BUTTON_CHANGE = 136293963L; + + /** * Creates a new instance. */ public AccessibilityServiceInfo() { @@ -623,13 +648,23 @@ public class AccessibilityServiceInfo implements Parcelable { } /** - * Updates the properties that an AccessibilitySerivice can change dynamically. + * Updates the properties that an AccessibilityService can change dynamically. + * <p> + * Note: A11y services targeting APIs > Q, it cannot update flagRequestAccessibilityButton + * dynamically. + * </p> * + * @param platformCompat The platform compat service to check the compatibility change. * @param other The info from which to update the properties. * * @hide */ - public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) { + public void updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, + AccessibilityServiceInfo other) { + if (isRequestAccessibilityButtonChangeEnabled(platformCompat)) { + other.flags &= ~FLAG_REQUEST_ACCESSIBILITY_BUTTON; + other.flags |= (flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON); + } eventTypes = other.eventTypes; packageNames = other.packageNames; feedbackType = other.feedbackType; @@ -639,6 +674,21 @@ public class AccessibilityServiceInfo implements Parcelable { flags = other.flags; } + private boolean isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat) { + if (mResolveInfo == null) { + return true; + } + try { + if (platformCompat != null) { + return platformCompat.isChangeEnabledByPackageName( + REQUEST_ACCESSIBILITY_BUTTON_CHANGE, mResolveInfo.serviceInfo.packageName, + mResolveInfo.serviceInfo.applicationInfo.uid); + } + } catch (RemoteException ignore) { + } + return mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q; + } + /** * @hide */ diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index 25cd342cb5e9..6470a04aefd6 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -103,8 +103,6 @@ import java.util.Arrays; * When writing an activity to satisfy these requests one must pass in the AccountManagerResponse * and return the result via that response when the activity finishes (or whenever else the * activity author deems it is the correct time to respond). - * The {@link AccountAuthenticatorActivity} handles this, so one may wish to extend that when - * writing activities to handle these requests. */ public abstract class AbstractAccountAuthenticator { private static final String TAG = "AccountAuthenticator"; diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java index 967aa0424b1d..65ba35ff9e8d 100644 --- a/core/java/android/accounts/AccountAuthenticatorActivity.java +++ b/core/java/android/accounts/AccountAuthenticatorActivity.java @@ -32,7 +32,11 @@ import android.os.Bundle; * This result will be sent as the result of the request when the activity finishes. If this * is never set or if it is set to null then error {@link AccountManager#ERROR_CODE_CANCELED} * will be called on the response. + * + * @deprecated Applications should extend Activity themselves. This class is not compatible with + * AppCompat, and the functionality it provides is not complex. */ +@Deprecated public class AccountAuthenticatorActivity extends Activity { private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null; private Bundle mResultBundle = null; diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ac8b604ad103..9aca22360fd8 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -44,6 +44,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); + // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text) + void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId); @UnsupportedAppUsage diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl index f2c9f615c03f..f5809ba627ff 100644 --- a/core/java/android/app/IUiModeManager.aidl +++ b/core/java/android/app/IUiModeManager.aidl @@ -25,7 +25,7 @@ interface IUiModeManager { * Enables the car mode. Only the system can do this. * @hide */ - void enableCarMode(int flags); + void enableCarMode(int flags, int priority, String callingPackage); /** * Disables the car mode. @@ -34,6 +34,12 @@ interface IUiModeManager { void disableCarMode(int flags); /** + * Disables car mode (the original version is marked unsupported app usage so cannot be changed + * for the time being). + */ + void disableCarModeByCallingPackage(int flags, String callingPackage); + + /** * Return the current running mode. */ int getCurrentModeType(); @@ -62,4 +68,9 @@ interface IUiModeManager { * Tells if Night mode is locked or not. */ boolean isNightModeLocked(); + + /** + * @hide + */ + boolean setNightModeActivated(boolean active); } diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index 92bfee24d402..38ae5da0d815 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -517,7 +517,7 @@ public final class StatsManager { } } - private static class PullAtomCallbackInternal extends IPullAtomCallback.Stub { + private static class PullAtomCallbackInternal extends IPullAtomCallback.Stub { public final int mAtomId; public final StatsPullAtomCallback mCallback; public final Executor mExecutor; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 69c174a47127..d0ba879bd10e 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -657,7 +657,7 @@ public final class SystemServiceRegistry { new CachedServiceFetcher<UiModeManager>() { @Override public UiModeManager createService(ContextImpl ctx) throws ServiceNotFoundException { - return new UiModeManager(); + return new UiModeManager(ctx.getOuterContext()); }}); registerService(Context.USB_SERVICE, UsbManager.class, diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 46316e1a254b..d8c030d7aacf 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -17,6 +17,10 @@ package android.app; import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; @@ -68,6 +72,25 @@ public class UiModeManager { * of the broadcast to {@link Activity#RESULT_CANCELED}. */ public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switched to car mode, either by being placed in a car + * dock or explicit action of the user. + * <p> + * In addition to the behavior for {@link #ACTION_ENTER_CAR_MODE}, this broadcast includes the + * package name of the app which requested to enter car mode in the + * {@link #EXTRA_CALLING_PACKAGE}. If an app requested to enter car mode using + * {@link #enableCarMode(int, int)} and specified a priority this will be specified in the + * {@link #EXTRA_PRIORITY}. + * + * This is primarily intended to be received by other components of the Android OS. + * <p> + * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES} + * @hide + */ + @SystemApi + public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = + "android.app.action.ENTER_CAR_MODE_PRIORITIZED"; /** * Broadcast sent when the device's UI has switch away from car mode back @@ -75,6 +98,28 @@ public class UiModeManager { * when the user exits car mode. */ public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switched away from car mode back to normal mode. + * Typically used by a car mode app, to dismiss itself when the user exits car mode. + * <p> + * In addition to the behavior for {@link #ACTION_EXIT_CAR_MODE}, this broadcast includes the + * package name of the app which requested to exit car mode in {@link #EXTRA_CALLING_PACKAGE}. + * If an app requested to enter car mode using {@link #enableCarMode(int, int)} and specified a + * priority this will be specified in the {@link #EXTRA_PRIORITY} when exiting car mode. + * <p> + * If {@link #DISABLE_CAR_MODE_ALL_PRIORITIES} is used when disabling car mode (i.e. this is + * initiated by the user via the persistent car mode notification), this broadcast is sent once + * for each priority level for which car mode is being disabled. + * <p> + * This is primarily intended to be received by other components of the Android OS. + * <p> + * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES} + * @hide + */ + @SystemApi + public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = + "android.app.action.EXIT_CAR_MODE_PRIORITIZED"; /** * Broadcast sent when the device's UI has switched to desk mode, @@ -97,6 +142,24 @@ public class UiModeManager { */ public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE"; + /** + * String extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and + * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the package name of the app which + * requested to enter or exit car mode. + * @hide + */ + @SystemApi + public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE"; + + /** + * Integer extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and + * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the priority level at which car mode + * is being disabled. + * @hide + */ + @SystemApi + public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY"; + /** @hide */ @IntDef(prefix = { "MODE_" }, value = { MODE_NIGHT_AUTO, @@ -126,10 +189,21 @@ public class UiModeManager { private IUiModeManager mService; + /** + * Context required for getting the opPackageName of API caller; maybe be {@code null} if the + * old constructor marked with UnSupportedAppUsage is used. + */ + private @Nullable Context mContext; + @UnsupportedAppUsage /*package*/ UiModeManager() throws ServiceNotFoundException { + this(null /* context */); + } + + /*package*/ UiModeManager(Context context) throws ServiceNotFoundException { mService = IUiModeManager.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE)); + mContext = context; } /** @@ -152,6 +226,14 @@ public class UiModeManager { */ public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 0x0002; + /** @hide */ + @IntDef(prefix = { "ENABLE_CAR_MODE_" }, value = { + ENABLE_CAR_MODE_GO_CAR_HOME, + ENABLE_CAR_MODE_ALLOW_SLEEP + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EnableCarMode {} + /** * Force device into car mode, like it had been placed in the car dock. * This will cause the device to switch to the car home UI as part of @@ -159,9 +241,54 @@ public class UiModeManager { * @param flags Must be 0. */ public void enableCarMode(int flags) { + enableCarMode(DEFAULT_PRIORITY, flags); + } + + /** + * Force device into car mode, like it had been placed in the car dock. This will cause the + * device to switch to the car home UI as part of the mode switch. + * <p> + * An app may request to enter car mode when the system is already in car mode. The app may + * specify a "priority" when entering car mode. The device will remain in car mode + * (i.e. {@link #getCurrentModeType()} is {@link Configuration#UI_MODE_TYPE_CAR}) as long as + * there is a priority level at which car mode have been enabled. For example assume app A + * enters car mode at priority level 100, and then app B enters car mode at the default priority + * (0). If app A exits car mode, the device will remain in car mode until app B exits car mode. + * <p> + * Specifying a priority level when entering car mode is important in cases where multiple apps + * on a device implement a car-mode {@link android.telecom.InCallService} (see + * {@link android.telecom.TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}). The + * {@link android.telecom.InCallService} associated with the highest priority app which entered + * car mode will be bound to by Telecom and provided with information about ongoing calls on + * the device. + * <p> + * System apps holding the required permission can enable car mode when the app determines the + * correct conditions exist for that app to be in car mode. The device maker should ensure that + * where multiple apps exist on the device which can potentially enter car mode, appropriate + * priorities are used to ensure that calls delivered by the + * {@link android.telecom.InCallService} API are delivered to the highest priority app. + * If app A and app B can both potentially enable car mode, and it is desired that app B is the + * one which should receive call information, the priority for app B should be higher than the + * one for app A. + * <p> + * When an app uses a priority to enable car mode, they can disable car mode at the specified + * priority level using {@link #disableCarMode(int)}. An app may only enable car mode at a + * single priority. + * <p> + * Public apps are assumed to enter/exit car mode at {@link #DEFAULT_PRIORITY}. + * + * @param priority The declared priority for the caller. + * @param flags Car mode flags. + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) + public void enableCarMode(@IntRange(from = 0) int priority, @EnableCarMode int flags) { if (mService != null) { try { - mService.enableCarMode(flags); + mService.enableCarMode(flags, priority, + mContext == null ? null : mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -176,15 +303,44 @@ public class UiModeManager { * being in car mode). */ public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001; + + /** + * Flag for use with {@link #disableCarMode(int)}: Disables car mode at ALL priority levels. + * Primarily intended for use from {@link com.android.internal.app.DisableCarModeActivity} to + * provide the user with a means to exit car mode at all priority levels. + * @hide + */ + public static final int DISABLE_CAR_MODE_ALL_PRIORITIES = 0x0002; + + /** @hide */ + @IntDef(prefix = { "DISABLE_CAR_MODE_" }, value = { + DISABLE_CAR_MODE_GO_HOME + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisableCarMode {} + + /** + * The default priority used for entering car mode. + * <p> + * Callers of the {@link UiModeManager#enableCarMode(int)} priority will be assigned the + * default priority. + * <p> + * System apps can specify a priority other than the default priority when using + * {@link UiModeManager#enableCarMode(int, int)} to enable car mode. + * @hide + */ + @SystemApi + public static final int DEFAULT_PRIORITY = 0; /** * Turn off special mode if currently in car mode. - * @param flags May be 0 or {@link #DISABLE_CAR_MODE_GO_HOME}. + * @param flags One of the disable car mode flags. */ - public void disableCarMode(int flags) { + public void disableCarMode(@DisableCarMode int flags) { if (mService != null) { try { - mService.disableCarMode(flags); + mService.disableCarModeByCallingPackage(flags, + mContext == null ? null : mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -317,4 +473,18 @@ public class UiModeManager { } return true; } + + /** + * @hide* + */ + public boolean setNightModeActivated(boolean active) { + if (mService != null) { + try { + return mService.setNightModeActivated(active); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 566b38738dc1..9d152a7faf44 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1734,6 +1734,56 @@ public final class BluetoothAdapter { } /** + * Connects all enabled and supported bluetooth profiles between the local and remote device + * + * @param device is the remote device with which to connect these profiles + * @return true if all profiles successfully connected, false if an error occurred + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.connectAllEnabledProfiles(device); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + + /** + * Disconnects all enabled and supported bluetooth profiles between the local and remote device + * + * @param device is the remote device with which to disconnect these profiles + * @return true if all profiles successfully disconnected, false if an error occurred + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.disconnectAllEnabledProfiles(device); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + + /** * Return true if the multi advertisement is supported by the chipset * * @return true if Multiple Advertisement feature is supported diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 19f42b6a4c9e..0be3eca8239e 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1095,24 +1095,6 @@ public final class BluetoothDevice implements Parcelable { } /** - * Get the Bluetooth alias of the remote device. - * If Alias is null, get the Bluetooth name instead. - * - * @return the Bluetooth alias, or null if no alias or there was a problem - * @hide - * @see #getAlias() - * @see #getName() - */ - @UnsupportedAppUsage(publicAlternatives = "Use {@link #getName()} instead.") - public String getAliasName() { - String name = getAlias(); - if (name == null) { - name = getName(); - } - return name; - } - - /** * Get the most recent identified battery level of this Bluetooth device * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index dabe0fdac39a..f5aa01458481 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -324,4 +324,54 @@ public interface BluetoothProfile { return "STATE_UNKNOWN"; } } + + /** + * Convert an integer value of profile ID into human readable string + * + * @param profile profile ID + * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined. + * @hide + */ + static String getProfileName(int profile) { + switch(profile) { + case HEADSET: + return "HEADSET"; + case A2DP: + return "A2DP"; + case HID_HOST: + return "HID_HOST"; + case PAN: + return "PAN"; + case PBAP: + return "PBAP"; + case GATT: + return "GATT"; + case GATT_SERVER: + return "GATT_SERVER"; + case MAP: + return "MAP"; + case SAP: + return "SAP"; + case A2DP_SINK: + return "A2DP_SINK"; + case AVRCP_CONTROLLER: + return "AVRCP_CONTROLLER"; + case AVRCP: + return "AVRCP"; + case HEADSET_CLIENT: + return "HEADSET_CLIENT"; + case PBAP_CLIENT: + return "PBAP_CLIENT"; + case MAP_CLIENT: + return "MAP_CLIENT"; + case HID_DEVICE: + return "HID_DEVICE"; + case OPP: + return "OPP"; + case HEARING_AID: + return "HEARING_AID"; + default: + return "UNKNOWN_PROFILE"; + } + } } diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index b04f7810ed45..e44d6ae40356 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -672,7 +672,6 @@ public class ContextWrapper extends Context { /** @hide */ @Override @Nullable - @SystemApi public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, @NonNull IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler) { diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 070e282a0eb2..2d9ca67a236d 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -38,18 +38,13 @@ import android.util.SparseArray; import android.util.TypedValue; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import libcore.io.IoUtils; - -import java.io.BufferedReader; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.channels.FileLock; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -176,7 +171,7 @@ public final class AssetManager implements AutoCloseable { public AssetManager() { final ApkAssets[] assets; synchronized (sSync) { - createSystemAssetsInZygoteLocked(); + createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); assets = sSystemApkAssets; } @@ -205,17 +200,19 @@ public final class AssetManager implements AutoCloseable { /** * This must be called from Zygote so that system assets are shared by all applications. + * @hide */ @GuardedBy("sSync") - private static void createSystemAssetsInZygoteLocked() { - if (sSystem != null) { + @VisibleForTesting + public static void createSystemAssetsInZygoteLocked(boolean reinitialize, + String frameworkPath) { + if (sSystem != null || reinitialize) { return; } - try { final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); - apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/)); + apkAssets.add(ApkAssets.loadFromPath(frameworkPath, true /*system*/)); final String[] systemIdmapPaths = nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); if (systemIdmapPaths != null) { for (String idmapPath : systemIdmapPaths) { @@ -236,42 +233,6 @@ public final class AssetManager implements AutoCloseable { } /** - * Loads the static runtime overlays declared in /data/resource-cache/overlays.list. - * Throws an exception if the file is corrupt or if loading the APKs referenced by the file - * fails. Returns quietly if the overlays.list file doesn't exist. - * @param outApkAssets The list to fill with the loaded ApkAssets. - */ - private static void loadStaticRuntimeOverlays(ArrayList<ApkAssets> outApkAssets) - throws IOException { - final FileInputStream fis; - try { - fis = new FileInputStream("/data/resource-cache/overlays.list"); - } catch (FileNotFoundException e) { - // We might not have any overlays, this is fine. We catch here since ApkAssets - // loading can also fail with the same exception, which we would want to propagate. - Log.i(TAG, "no overlays.list file found"); - return; - } - - try { - // Acquire a lock so that any idmap scanning doesn't impact the current set. - // The order of this try-with-resources block matters. We must release the lock, and - // then close the file streams when exiting the block. - try (final BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - final FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE, true /*shared*/)) { - for (String line; (line = br.readLine()) != null; ) { - final String idmapPath = line.split(" ")[1]; - outApkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); - } - } - } finally { - // When BufferedReader is closed above, FileInputStream is closed as well. But let's be - // paranoid. - IoUtils.closeQuietly(fis); - } - } - - /** * Return a global shared asset manager that provides access to only * system assets (no application assets). * @hide @@ -279,7 +240,7 @@ public final class AssetManager implements AutoCloseable { @UnsupportedAppUsage public static AssetManager getSystem() { synchronized (sSync) { - createSystemAssetsInZygoteLocked(); + createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); return sSystem; } } @@ -1645,7 +1606,6 @@ public final class AssetManager implements AutoCloseable { private static native long nativeAssetGetLength(long assetPtr); private static native long nativeAssetGetRemainingLength(long assetPtr); - private static native void nativeVerifySystemIdmaps(); private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); private static native @Nullable Map nativeGetOverlayableMap(long ptr, @NonNull String packageName); diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 45a9cf5ab869..928df3c4ff97 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -28,15 +28,14 @@ import java.lang.reflect.Modifier; * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}. Each Handler * instance is associated with a single thread and that thread's message - * queue. When you create a new Handler, it is bound to the thread / - * message queue of the thread that is creating it -- from that point on, - * it will deliver messages and runnables to that message queue and execute - * them as they come out of the message queue. - * + * queue. When you create a new Handler it is bound to a {@link Looper}. + * It will deliver messages and runnables to that Looper's message + * queue and execute them on that Looper's thread. + * * <p>There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed at some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. - * + * * <p>Scheduling messages is accomplished with the * {@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, @@ -114,7 +113,18 @@ public class Handler { * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. + * + * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs + * where operations are silently lost (if the Handler is not expecting new tasks and quits), + * crashes (if a handler is sometimes created on a thread without a Looper active), or race + * conditions, where the thread a handler is associated with is not what the author + * anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper + * explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or + * similar. If the implicit thread local behavior is required for compatibility, use + * {@code new Handler(Looper.myLooper())} to make it clear to readers. + * */ + @Deprecated public Handler() { this(null, false); } @@ -128,7 +138,17 @@ public class Handler { * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. - */ + * + * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs + * where operations are silently lost (if the Handler is not expecting new tasks and quits), + * crashes (if a handler is sometimes created on a thread without a Looper active), or race + * conditions, where the thread a handler is associated with is not what the author + * anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper + * explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or + * similar. If the implicit thread local behavior is required for compatibility, use + * {@code new Handler(Looper.myLooper(), callback)} to make it clear to readers. + */ + @Deprecated public Handler(@Nullable Callback callback) { this(callback, false); } diff --git a/core/java/android/provider/AndroidDeviceConfig.java b/core/java/android/provider/AndroidDeviceConfig.java new file mode 100644 index 000000000000..424632fca0a4 --- /dev/null +++ b/core/java/android/provider/AndroidDeviceConfig.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.provider; + +import android.annotation.TestApi; + +/** + * Interface for accessing keys belonging to {@link DeviceConfig#NAMESPACE_ANDROID}. + * @hide + */ +@TestApi +public interface AndroidDeviceConfig { + + /** + * Key for accessing the system gesture exclusion limit (an integer in dp). + * + * <p>Note: On Devices running Q, this key is in the "android:window_manager" namespace. + * + * @see android.provider.DeviceConfig#NAMESPACE_ANDROID + */ + String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp"; + + /** + * Key for controlling whether system gestures are implicitly excluded by windows requesting + * sticky immersive mode from apps that are targeting an SDK prior to Q. + * + * <p>Note: On Devices running Q, this key is in the "android:window_manager" namespace. + * + * @see android.provider.DeviceConfig#NAMESPACE_ANDROID + */ + String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = + "system_gestures_excluded_by_pre_q_sticky_immersive"; + +} diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java index dd2ea81d747b..7995f2285482 100644 --- a/core/java/android/provider/BlockedNumberContract.java +++ b/core/java/android/provider/BlockedNumberContract.java @@ -16,6 +16,8 @@ package android.provider; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.WorkerThread; import android.content.Context; import android.net.Uri; @@ -153,7 +155,12 @@ public class BlockedNumberContract { /** The authority for the blocked number provider */ public static final String AUTHORITY = "com.android.blockednumber"; - /** A content:// style uri to the authority for the blocked number provider */ + /** + * A content:// style uri to the authority for the blocked number provider + * @hide + */ + @NonNull + @SystemApi public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); private static final String LOG_TAG = BlockedNumberContract.class.getSimpleName(); @@ -239,6 +246,7 @@ public class BlockedNumberContract { * blocked. * @hide */ + @SystemApi public static final int STATUS_NOT_BLOCKED = 0; /** @@ -246,6 +254,7 @@ public class BlockedNumberContract { * because it is in the list of blocked numbers maintained by the provider. * @hide */ + @SystemApi public static final int STATUS_BLOCKED_IN_LIST = 1; /** @@ -253,6 +262,7 @@ public class BlockedNumberContract { * because it is from a restricted number. * @hide */ + @SystemApi public static final int STATUS_BLOCKED_RESTRICTED = 2; /** @@ -260,6 +270,7 @@ public class BlockedNumberContract { * because it is from an unknown number. * @hide */ + @SystemApi public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; /** @@ -267,6 +278,7 @@ public class BlockedNumberContract { * because it is from a pay phone. * @hide */ + @SystemApi public static final int STATUS_BLOCKED_PAYPHONE = 4; /** @@ -274,12 +286,14 @@ public class BlockedNumberContract { * because it is from a number not in the users contacts. * @hide */ + @SystemApi public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; /** * Integer reason indicating whether a call was blocked, and if so why. * @hide */ + @SystemApi public static final String RES_BLOCK_STATUS = "block_status"; /** @hide */ @@ -290,6 +304,31 @@ public class BlockedNumberContract { "can_current_user_block_numbers"; /** @hide */ + @SystemApi + public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact"; + + /** @hide */ + public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression"; + + /** @hide */ + @SystemApi + public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number"; + + /** @hide */ + public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS = + "get_block_suppression_status"; + + /** @hide */ + public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION = + "should_show_emergency_call_notification"; + + /** @hide */ + public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting"; + + /** @hide */ + public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting"; + + /** @hide */ public static final String RES_CAN_BLOCK_NUMBERS = "can_block"; /** @hide */ @@ -406,26 +445,11 @@ public class BlockedNumberContract { public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED = "android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED"; - public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact"; - - public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression"; - - public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number"; - - public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS = - "get_block_suppression_status"; - - public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION = - "should_show_emergency_call_notification"; - public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed"; public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP = "blocking_suppressed_until_timestamp"; - public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting"; - public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting"; - /* Preference key of block numbers not in contacts setting. */ public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED = "block_numbers_not_in_contacts_setting"; diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 2cb0750a3346..30db6382fcd6 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -43,8 +43,6 @@ import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.PhoneConstants; - import java.util.List; /** @@ -613,7 +611,7 @@ public class CallLog { * if the contact is unknown. * @param context the context used to get the ContentResolver * @param number the phone number to be added to the calls db - * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which + * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which * is set by the network and denotes the number presenting rules for * "allowed", "payphone", "restricted" or "unknown" * @param callType enumerated values for "incoming", "outgoing", or "missed" @@ -648,7 +646,7 @@ public class CallLog { * @param number the phone number to be added to the calls db * @param viaNumber the secondary number that the incoming call received with. If the * call was received with the SIM assigned number, then this field must be ''. - * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which + * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which * is set by the network and denotes the number presenting rules for * "allowed", "payphone", "restricted" or "unknown" * @param callType enumerated values for "incoming", "outgoing", or "missed" @@ -689,7 +687,7 @@ public class CallLog { * if it was outgoing. Otherwise it is ''. * @param viaNumber the secondary number that the incoming call received with. If the * call was received with the SIM assigned number, then this field must be ''. - * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which + * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which * is set by the network and denotes the number presenting rules for * "allowed", "payphone", "restricted" or "unknown" * @param callType enumerated values for "incoming", "outgoing", or "missed" @@ -1051,22 +1049,22 @@ public class CallLog { /** * Remap network specified number presentation types - * PhoneConstants.PRESENTATION_xxx to calllog number presentation types + * TelecomManager.PRESENTATION_xxx to calllog number presentation types * Calls.PRESENTATION_xxx, in order to insulate the persistent calllog * from any future radio changes. * If the number field is empty set the presentation type to Unknown. */ private static int getLogNumberPresentation(String number, int presentation) { - if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) { + if (presentation == TelecomManager.PRESENTATION_RESTRICTED) { return presentation; } - if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) { + if (presentation == TelecomManager.PRESENTATION_PAYPHONE) { return presentation; } if (TextUtils.isEmpty(number) - || presentation == PhoneConstants.PRESENTATION_UNKNOWN) { + || presentation == TelecomManager.PRESENTATION_UNKNOWN) { return PRESENTATION_UNKNOWN; } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 0401d7fb8d5d..1d7e33806e0c 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -314,13 +314,22 @@ public final class DeviceConfig { public static final String NAMESPACE_SETTINGS_UI = "settings_ui"; /** - * Namespace for window manager related features. The names to access the properties in this - * namespace should be defined in {@link WindowManager}. + * Namespace for android related features, i.e. for flags that affect not just a single + * component, but the entire system. + * + * The keys for this namespace are defined in {@link AndroidDeviceConfig}. * * @hide */ @TestApi - public static final String NAMESPACE_WINDOW_MANAGER = "android:window_manager"; + public static final String NAMESPACE_ANDROID = "android"; + + /** + * Namespace for window manager related features. + * + * @hide + */ + public static final String NAMESPACE_WINDOW_MANAGER = "window_manager"; /** * List of namespaces which can be read without READ_DEVICE_CONFIG permission @@ -348,48 +357,6 @@ public final class DeviceConfig { @TestApi public static final String NAMESPACE_PERMISSIONS = "permissions"; - /** - * Interface for accessing keys belonging to {@link #NAMESPACE_WINDOW_MANAGER}. - * @hide - */ - @TestApi - public interface WindowManager { - - /** - * Key for accessing the system gesture exclusion limit (an integer in dp). - * - * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER - * @hide - */ - @TestApi - String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp"; - - /** - * Key for controlling whether system gestures are implicitly excluded by windows requesting - * sticky immersive mode from apps that are targeting an SDK prior to Q. - * - * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER - * @hide - */ - @TestApi - String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = - "system_gestures_excluded_by_pre_q_sticky_immersive"; - - /** - * The minimum duration between gesture exclusion logging for a given window in - * milliseconds. - * - * Events that happen in-between will be silently dropped. - * - * A non-positive value disables logging. - * - * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER - * @hide - */ - String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS = - "system_gesture_exclusion_log_debounce_millis"; - } - private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners = diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index a0800910d1b3..f66a679ad87d 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -16,7 +16,10 @@ package android.telephony; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.Context; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -225,14 +228,33 @@ public class TelephonyRegistryManager { * @param slotIndex for which call state changed. Can be derived from subId except when subId is * invalid. * @param state latest call state. e.g, offhook, ringing - * @param incomingNumer incoming phone number. + * @param incomingNumber incoming phone number. * * @hide */ public void notifyCallStateChanged(int subId, int slotIndex, @CallState int state, - String incomingNumer) { + String incomingNumber) { try { - sRegistry.notifyCallState(slotIndex, subId, state, incomingNumer); + sRegistry.notifyCallState(slotIndex, subId, state, incomingNumber); + } catch (RemoteException ex) { + // system server crash + } + } + + /** + * Notify call state changed on all subscriptions. + * + * @param state latest call state. e.g, offhook, ringing + * @param incomingNumber incoming phone number. + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void notifyCallStateChangedForAllSubscriptions(@CallState int state, + @Nullable String incomingNumber) { + try { + sRegistry.notifyCallStateForAllSubs(state, incomingNumber); } catch (RemoteException ex) { // system server crash } @@ -594,9 +616,9 @@ public class TelephonyRegistryManager { * @hide */ public void notifyPreciseCallState(int subId, int slotIndex, - @PreciseCallStates int ringCallPreciseState, - @PreciseCallStates int foregroundCallPreciseState, - @PreciseCallStates int backgroundCallPreciseState) { + @PreciseCallStates int ringCallPreciseState, + @PreciseCallStates int foregroundCallPreciseState, + @PreciseCallStates int backgroundCallPreciseState) { try { sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState, foregroundCallPreciseState, backgroundCallPreciseState); diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 12a55c74bd3e..7e0974033fa7 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -55,7 +55,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true"); DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false"); - DEFAULT_FLAGS.put("settings_work_profile", "false"); + DEFAULT_FLAGS.put("settings_work_profile", "true"); DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false"); } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 27402a463d4f..187ab46b2e08 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2584,8 +2584,7 @@ public class Editor { * @return True when the TextView isFocused and has a valid zero-length selection (cursor). */ private boolean shouldBlink() { - if (!isCursorVisible() || !mTextView.isFocused() || - !mTextView.isVisibleToUser()) return false; + if (!isCursorVisible() || !mTextView.isFocused()) return false; final int start = mTextView.getSelectionStart(); if (start < 0) return false; diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index d58d858c3b8a..5cc0e0e5de25 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -66,6 +66,7 @@ import android.widget.RemoteViews.RemoteView; import com.android.internal.R; +import java.text.NumberFormat; import java.util.ArrayList; /** @@ -241,6 +242,8 @@ public class ProgressBar extends View { private boolean mAggregatedIsVisible; + private CharSequence mCustomStateDescription = null; + private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>(); /** @@ -1551,9 +1554,54 @@ public class ProgressBar extends View { } } + private float getPercent(int progress) { + final float maxProgress = getMax(); + final float minProgress = getMin(); + final float currentProgress = progress; + final float diffProgress = maxProgress - minProgress; + if (diffProgress <= 0.0f) { + return 0.0f; + } + final float percent = (currentProgress - minProgress) / diffProgress; + return Math.max(0.0f, Math.min(1.0f, percent)); + } + + /** + * Default percentage format of the state description based on progress, for example, + * "50 percent". + * + * @param progress the progress value, between {@link #getMin()} and {@link #getMax()} + * @return state description based on progress + */ + private CharSequence formatStateDescription(int progress) { + return NumberFormat.getPercentInstance(mContext.getResources().getConfiguration().locale) + .format(getPercent(progress)); + } + + /** + * This function is called when an instance or subclass sets the state description. Once this + * is called and the argument is not null, the app developer will be responsible for updating + * state description when progress changes and the default state description will not be used. + * App developers can restore the default behavior by setting the argument to null. If set + * progress is called first and then setStateDescription is called, two state change events + * will be merged by event throttling and we can still get the correct state description. + * + * @param stateDescription The state description. + */ + @Override + public void setStateDescription(@Nullable CharSequence stateDescription) { + mCustomStateDescription = stateDescription; + if (stateDescription == null) { + super.setStateDescription(formatStateDescription(mProgress)); + } else { + super.setStateDescription(stateDescription); + } + } + void onProgressRefresh(float scale, boolean fromUser, int progress) { - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + if (AccessibilityManager.getInstance(mContext).isEnabled() + && mCustomStateDescription == null) { + super.setStateDescription(formatStateDescription(mProgress)); } } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index d037337d4546..bdc2f9af2775 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -100,6 +100,8 @@ public class Toast { @UnsupportedAppUsage int mDuration; View mNextView; + // TODO(b/128611929): Remove this and check for null view when toast creation is in the system + boolean mIsCustomToast = false; /** * Construct an empty Toast object. You must call {@link #setView} before you @@ -140,7 +142,11 @@ public class Toast { final int displayId = mContext.getDisplayId(); try { - service.enqueueToast(pkg, tn, mDuration, displayId); + if (mIsCustomToast) { + service.enqueueToast(pkg, tn, mDuration, displayId); + } else { + service.enqueueTextToast(pkg, tn, mDuration, displayId); + } } catch (RemoteException e) { // Empty } @@ -160,6 +166,7 @@ public class Toast { * @see #getView */ public void setView(View view) { + mIsCustomToast = true; mNextView = view; } @@ -168,6 +175,7 @@ public class Toast { * @see #setView */ public View getView() { + mIsCustomToast = true; return mNextView; } diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java index 7943c613b357..d44312b716ba 100644 --- a/core/java/com/android/internal/app/DisableCarModeActivity.java +++ b/core/java/com/android/internal/app/DisableCarModeActivity.java @@ -33,7 +33,9 @@ public class DisableCarModeActivity extends Activity { try { IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface( ServiceManager.getService("uimode")); - uiModeManager.disableCarMode(UiModeManager.DISABLE_CAR_MODE_GO_HOME); + uiModeManager.disableCarModeByCallingPackage(UiModeManager.DISABLE_CAR_MODE_GO_HOME + | UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES, + getOpPackageName()); } catch (RemoteException e) { Log.e(TAG, "Failed to disable car mode", e); } diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 045a6800bb13..7dcb12c9e72b 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -171,6 +171,15 @@ interface IPlatformCompat void clearOverrides(in String packageName); /** + * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests. + * + * @param packageName The package name of the app whose overrides will be cleared. + * + */ + void clearOverridesForTest(in String packageName); + + + /** * Get configs for an application. * * @param appInfo The application whose config will be returned. diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java index 7a17253ffd35..b6d2dedc1bfd 100755 --- a/core/java/com/android/internal/util/function/pooled/OmniFunction.java +++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java @@ -30,10 +30,13 @@ import com.android.internal.util.function.OctConsumer; import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadConsumer; import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.QuadPredicate; import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; +import com.android.internal.util.function.QuintPredicate; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.TriPredicate; import com.android.internal.util.function.UndecConsumer; import com.android.internal.util.function.UndecFunction; @@ -59,7 +62,8 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> implements HeptConsumer<A, B, C, D, E, F, G>, OctConsumer<A, B, C, D, E, F, G, H>, NonaConsumer<A, B, C, D, E, F, G, H, I>, DecConsumer<A, B, C, D, E, F, G, H, I, J>, UndecConsumer<A, B, C, D, E, F, G, H, I, J, K>, - PooledPredicate<A>, BiPredicate<A, B>, PooledSupplier<R>, PooledRunnable, ThrowingRunnable, + PooledPredicate<A>, BiPredicate<A, B>, TriPredicate<A, B, C>, QuadPredicate<A, B, C, D>, + QuintPredicate<A, B, C, D, E>, PooledSupplier<R>, PooledRunnable, ThrowingRunnable, ThrowingSupplier<R>, PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); @@ -99,6 +103,21 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> implements } @Override + public boolean test(A o, B o2, C o3, D o4, E o5) { + return (Boolean) invoke(o, o2, o3, o4, o5, null, null, null, null, null, null); + } + + @Override + public boolean test(A o, B o2, C o3, D o4) { + return (Boolean) invoke(o, o2, o3, o4, null, null, null, null, null, null, null); + } + + @Override + public boolean test(A o, B o2, C o3) { + return (Boolean) invoke(o, o2, o3, null, null, null, null, null, null, null, null); + } + + @Override public boolean test(A o, B o2) { return (Boolean) invoke(o, o2, null, null, null, null, null, null, null, null, null); } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java index b9bf9337c3d6..d32ff060a8d7 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -33,10 +33,13 @@ import com.android.internal.util.function.OctConsumer; import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadConsumer; import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.QuadPredicate; import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; +import com.android.internal.util.function.QuintPredicate; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.TriPredicate; import com.android.internal.util.function.UndecConsumer; import com.android.internal.util.function.UndecFunction; import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType; @@ -346,6 +349,66 @@ public interface PooledLambda { } /** + * {@link PooledPredicate} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @return a {@link PooledPredicate}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3) } + */ + static <A, B, C> PooledPredicate<A> obtainPredicate( + TriPredicate<? super A, ? super B, ? super C> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, null, null, null, null, null, + null, null, null); + } + + /** + * {@link PooledPredicate} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @return a {@link PooledPredicate}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3, arg4) } + */ + static <A, B, C, D> PooledPredicate<A> obtainPredicate( + QuadPredicate<? super A, ? super B, ? super C, ? super D> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null, + null, null, null); + } + + /** + * {@link PooledPredicate} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 placeholder for a missing argument. Use {@link #__} to get one + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @return a {@link PooledPredicate}, equivalent to lambda: + * {@code (arg1) -> function(arg1, arg2, arg3, arg4, arg5) } + */ + static <A, B, C, D, E> PooledPredicate<A> obtainPredicate( + QuintPredicate<? super A, ? super B, ? super C, ? super D, ? super E> function, + ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4, E arg5) { + return acquire(PooledLambdaImpl.sPool, + function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null, + null, null, null); + } + + /** * {@link PooledFunction} factory * * @param function non-capturing lambda(typically an unbounded method reference) diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 4f7f18e1bf04..32d62fe2cdba 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -622,6 +622,8 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; + char dex2oatCpuSetBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX]; + char dex2oatCpuSetImageBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; @@ -911,6 +913,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option"); parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j", "-Ximage-compiler-option"); + parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=", + "-Xcompiler-option"); + parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=", + "-Ximage-compiler-option"); // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to // pass the instruction-set-features/variant as an image-compiler-option. diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 5c4dc2335822..ff596b440867 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -121,107 +121,6 @@ constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie; } -// This is called by zygote (running as user root) as part of preloadResources. -static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { - switch (pid_t pid = fork()) { - case -1: - PLOG(ERROR) << "failed to fork for idmap"; - break; - - // child - case 0: { - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata; - - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - - capheader.version = _LINUX_CAPABILITY_VERSION; - capheader.pid = 0; - - if (capget(&capheader, &capdata) != 0) { - PLOG(ERROR) << "capget"; - exit(1); - } - - capdata.effective = capdata.permitted; - if (capset(&capheader, &capdata) != 0) { - PLOG(ERROR) << "capset"; - exit(1); - } - - if (setgid(AID_SYSTEM) != 0) { - PLOG(ERROR) << "setgid"; - exit(1); - } - - if (setuid(AID_SYSTEM) != 0) { - PLOG(ERROR) << "setuid"; - exit(1); - } - - // Generic idmap parameters - const char* argv[11]; - int argc = 0; - struct stat st; - - memset(argv, 0, sizeof(argv)); - argv[argc++] = AssetManager::IDMAP_BIN; - argv[argc++] = "--scan"; - argv[argc++] = AssetManager::TARGET_PACKAGE_NAME; - argv[argc++] = AssetManager::TARGET_APK_PATH; - argv[argc++] = AssetManager::IDMAP_DIR; - - // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined, - // use VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in - // addition to VENDOR_OVERLAY_DIR. - std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY, - ""); - if (!overlay_theme_path.empty()) { - overlay_theme_path = - std::string(AssetManager::VENDOR_OVERLAY_DIR) + "/" + overlay_theme_path; - if (stat(overlay_theme_path.c_str(), &st) == 0) { - argv[argc++] = overlay_theme_path.c_str(); - } - } - - if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::VENDOR_OVERLAY_DIR; - } - - if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR; - } - - if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::SYSTEM_EXT_OVERLAY_DIR; - } - - if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::ODM_OVERLAY_DIR; - } - - if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::OEM_OVERLAY_DIR; - } - - // Finally, invoke idmap (if any overlay directory exists) - if (argc > 5) { - execv(AssetManager::IDMAP_BIN, (char* const*)argv); - PLOG(ERROR) << "failed to execv for idmap"; - exit(1); // should never get here - } else { - exit(0); - } - } break; - - // parent - default: - waitpid(pid, nullptr, 0); - break; - } -} - static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env, jclass /*clazz*/) { // --input-directory can be given multiple times, but idmap2 expects the directory to exist @@ -1665,7 +1564,6 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength}, // System/idmap related methods. - {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;", diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 653d381e2960..56e879090665 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -244,7 +244,8 @@ message AppWindowTokenProto { optional int32 num_drawn_windows = 15; optional bool all_drawn = 16; optional bool last_all_drawn = 17; - optional bool removed = 18; + // Will be removed soon + optional bool removed = 18 [deprecated=true]; optional IdentifierProto starting_window = 19; optional bool starting_displayed = 20; optional bool starting_moved = 21; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e1ca1f6f346c..62001aabca76 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -108,6 +108,8 @@ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" /> <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" /> + <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIVILEGED" /> + <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIVILEGED" /> <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" /> <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" /> <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" /> @@ -4346,6 +4348,21 @@ it will be ignored. @hide --> <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" + android:protectionLevel="signature|privileged" /> + + <!-- @SystemApi Allows entering or exiting car mode using a specified priority. + This permission is required to use UiModeManager while specifying a priority for the calling + app. A device manufacturer uses this permission to prioritize the apps which can + potentially request to enter car-mode on a device to help establish the correct behavior + where multiple such apps are active at the same time. + @hide --> + <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" + android:protectionLevel="signature|privileged" /> + + <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or + ACTION_EXIT_CAR_MODE_PRIVILEGED. + @hide --> + <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES" android:protectionLevel="signature|privileged" /> <!-- The system process is explicitly the only one allowed to launch the diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e6f038a2829c..74bb2cf6658d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -529,7 +529,7 @@ - TYPE_ETHERNET (9) is prepended to this list, and - - the return value of TelephonyManager.isTetherApnRequired() + - the return value of TelephonyManager.isTetheringApnRequired() determines how the array is further modified: * TRUE (DUN REQUIRED). diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index d2ce4e0a03b9..fe539e4ca22b 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -244,6 +244,7 @@ applications that come with the platform <permission name="android.permission.BIND_CONNECTION_SERVICE"/> <permission name="android.permission.BIND_INCALL_SERVICE"/> <permission name="android.permission.CALL_PRIVILEGED"/> + <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MANAGE_ROLE_HOLDERS"/> @@ -338,6 +339,8 @@ applications that come with the platform <permission name="android.permission.SYSTEM_CAMERA" /> <!-- Permission required to test ExplicitHealthCheckServiceImpl. --> <permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/> + <!-- Permission required for UiModeManager cts test. --> + <permission name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 753f8a05cbe3..ed19a37de460 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -169,12 +169,6 @@ "group": "WM_DEBUG_RESIZE", "at": "com\/android\/server\/wm\/WindowState.java" }, - "-1797409732": { - "message": "Skipping %s because %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, "-1782453012": { "message": "Checking theme of starting window: 0x%x", "level": "VERBOSE", @@ -1453,12 +1447,6 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "789829331": { - "message": "Aborted starting %s: removed=%b startingData=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "791468751": { "message": "Pausing rotation during re-position", "level": "DEBUG", @@ -1927,6 +1915,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1822843721": { + "message": "Aborted starting %s: startingData=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1831008694": { "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", "level": "DEBUG", diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 3c4783590c16..d9ed5f32cfc3 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -348,16 +348,6 @@ public class KeyStore { return list(prefix, UID_SELF); } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public boolean reset() { - try { - return mBinder.reset() == NO_ERROR; - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return false; - } - } - /** * Attempt to lock the keystore for {@code user}. * @@ -922,15 +912,26 @@ public class KeyStore { } } - public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature, - byte[] entropy) { + /** + * Android KeyStore finish operation. + * + * @param token Authentication token. + * @param arguments Keymaster arguments + * @param input Optional additional input data. + * @param signature Optional signature to be verified. + * @param entropy Optional additional entropy + * @return OperationResult that will indicate success or error of the operation. + */ + public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input, + byte[] signature, byte[] entropy) { OperationPromise promise = new OperationPromise(); try { mBinder.asBinder().linkToDeath(promise, 0); arguments = arguments != null ? arguments : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; + input = input != null ? input : new byte[0]; signature = signature != null ? signature : new byte[0]; - int errorCode = mBinder.finish(promise, token, arguments, signature, entropy); + int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy); if (errorCode == NO_ERROR) { return promise.getFuture().get(); } else { @@ -948,7 +949,7 @@ public class KeyStore { } public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) { - return finish(token, arguments, signature, null); + return finish(token, arguments, null, signature, null); } private class KeystoreResultPromise diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java index 441ee660b53a..c6515efd2c61 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java @@ -432,7 +432,7 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC } @Override - public OperationResult finish(byte[] signature, byte[] additionalEntropy) { + public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) { if ((additionalEntropy != null) && (additionalEntropy.length > 0)) { throw new ProviderException("AAD stream does not support additional entropy"); } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java index 3dc884eb38ad..17aacb9756aa 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -210,13 +210,9 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } } if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { - if (mKeySizeBits < 64) { + if (mKeySizeBits < 64 || mKeySizeBits > 512) { throw new InvalidAlgorithmParameterException( - "HMAC key size must be at least 64 bits."); - } - if (mKeySizeBits > 512 && spec.isStrongBoxBacked()) { - throw new InvalidAlgorithmParameterException( - "StrongBox HMAC key size must be smaller than 512 bits."); + "HMAC key sizes must be within 64-512 bits, inclusive."); } // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java index e0304787142d..75bea26aecef 100644 --- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java @@ -62,7 +62,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't * be reached. */ - OperationResult finish(byte[] siganture, byte[] additionalEntropy); + OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy); } // Binder buffer is about 1MB, but it's shared between all active transactions of the process. @@ -217,7 +217,8 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS byte[] output = update(input, inputOffset, inputLength); output = ArrayUtils.concat(output, flush()); - OperationResult opResult = mKeyStoreStream.finish(signature, additionalEntropy); + OperationResult opResult = mKeyStoreStream.finish(EmptyArray.BYTE, signature, + additionalEntropy); if (opResult == null) { throw new KeyStoreConnectException(); } else if (opResult.resultCode != KeyStore.NO_ERROR) { @@ -334,8 +335,8 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS } @Override - public OperationResult finish(byte[] signature, byte[] additionalEntropy) { - return mKeyStore.finish(mOperationToken, null, signature, additionalEntropy); + public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) { + return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy); } } } diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING new file mode 100644 index 000000000000..2f386271dcb7 --- /dev/null +++ b/location/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsLocationCoarseTestCases" + }, + { + "name": "CtsLocationNoneTestCases" + } + ] +} diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 2380077157c1..445420f130d0 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -66,9 +66,9 @@ public final class MediaRoute2Info implements Parcelable { @Nullable final String mProviderId; @NonNull - final String mName; + final CharSequence mName; @Nullable - final String mDescription; + final CharSequence mDescription; @Nullable final String mClientPackageName; @NonNull @@ -98,8 +98,8 @@ public final class MediaRoute2Info implements Parcelable { MediaRoute2Info(@NonNull Parcel in) { mId = in.readString(); mProviderId = in.readString(); - mName = in.readString(); - mDescription = in.readString(); + mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mClientPackageName = in.readString(); mSupportedCategories = in.createStringArrayList(); mVolume = in.readInt(); @@ -194,12 +194,12 @@ public final class MediaRoute2Info implements Parcelable { } @NonNull - public String getName() { + public CharSequence getName() { return mName; } @Nullable - public String getDescription() { + public CharSequence getDescription() { return mDescription; } @@ -277,8 +277,8 @@ public final class MediaRoute2Info implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(mId); dest.writeString(mProviderId); - dest.writeString(mName); - dest.writeString(mDescription); + TextUtils.writeToParcel(mName, dest, flags); + TextUtils.writeToParcel(mDescription, dest, flags); dest.writeString(mClientPackageName); dest.writeStringList(mSupportedCategories); dest.writeInt(mVolume); @@ -308,8 +308,8 @@ public final class MediaRoute2Info implements Parcelable { public static final class Builder { String mId; String mProviderId; - String mName; - String mDescription; + CharSequence mName; + CharSequence mDescription; String mClientPackageName; List<String> mSupportedCategories; int mVolume; @@ -317,13 +317,7 @@ public final class MediaRoute2Info implements Parcelable { int mVolumeHandling = PLAYBACK_VOLUME_FIXED; Bundle mExtras; - public Builder(@NonNull String id, @NonNull String name) { - if (TextUtils.isEmpty(id)) { - throw new IllegalArgumentException("id must not be null or empty"); - } - if (TextUtils.isEmpty(name)) { - throw new IllegalArgumentException("name must not be null or empty"); - } + public Builder(@NonNull String id, @NonNull CharSequence name) { setId(id); setName(name); mSupportedCategories = new ArrayList<>(); @@ -379,10 +373,8 @@ public final class MediaRoute2Info implements Parcelable { * Sets the user-visible name of the route. */ @NonNull - public Builder setName(@NonNull String name) { - if (TextUtils.isEmpty(name)) { - throw new IllegalArgumentException("name must not be null or empty"); - } + public Builder setName(@NonNull CharSequence name) { + Objects.requireNonNull(name, "name must not be null"); mName = name; return this; } diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 8928c47cf4bb..64f81d5c34fb 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -38,7 +38,7 @@ static constexpr bool kStealActiveStream_OldestFirst = true; // kPlayOnCallingThread = true prior to R. // Changing to false means calls to play() are almost instantaneous instead of taking around // ~10ms to launch the AudioTrack. It is perhaps 100x faster. -static constexpr bool kPlayOnCallingThread = false; +static constexpr bool kPlayOnCallingThread = true; // Amount of time for a StreamManager thread to wait before closing. static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND; @@ -167,6 +167,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound, if (!stream->getPairStream()->hasSound()) { if (stream->getSoundID() == soundID) { newStream = stream; + fromAvailableQueue = false; break; } else if (newStream == nullptr) { newStream = stream; diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java index 240e7d1b6357..d0f7c780ceb2 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -82,6 +82,11 @@ public class MediaRouterManagerTest { public static final String CATEGORY_SPECIAL = "com.android.mediarouteprovider.CATEGORY_SPECIAL"; + // system routes + private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; + private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO"; + private static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO"; + private static final int TIMEOUT_MS = 5000; private Context mContext; @@ -90,13 +95,17 @@ public class MediaRouterManagerTest { private Executor mExecutor; private String mPackageName; - private static final List<String> CONTROL_CATEGORIES_ALL = new ArrayList(); - private static final List<String> CONTROL_CATEGORIES_SPECIAL = new ArrayList(); + private static final List<String> CATEGORIES_ALL = new ArrayList(); + private static final List<String> CATEGORIES_SPECIAL = new ArrayList(); + private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>(); static { - CONTROL_CATEGORIES_ALL.add(CATEGORY_SAMPLE); - CONTROL_CATEGORIES_ALL.add(CATEGORY_SPECIAL); + CATEGORIES_ALL.add(CATEGORY_SAMPLE); + CATEGORIES_ALL.add(CATEGORY_SPECIAL); + CATEGORIES_ALL.add(CATEGORY_LIVE_AUDIO); + + CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL); - CONTROL_CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL); + CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO); } @Before @@ -153,7 +162,7 @@ public class MediaRouterManagerTest { mRouter2.registerCallback(mExecutor, routerCallback); Map<String, MediaRoute2Info> routes = - waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL); + waitAndGetRoutesWithManager(CATEGORIES_ALL); CountDownLatch latch = new CountDownLatch(1); MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() { @@ -187,7 +196,7 @@ public class MediaRouterManagerTest { mManager.registerCallback(mExecutor, mockCallback); Map<String, MediaRoute2Info> routes = - waitAndGetRoutesWithManager(CONTROL_CATEGORIES_SPECIAL); + waitAndGetRoutesWithManager(CATEGORIES_SPECIAL); Assert.assertEquals(1, routes.size()); Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); @@ -203,7 +212,7 @@ public class MediaRouterManagerTest { MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); mRouter2.registerCallback(mExecutor, mockCallback); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_SPECIAL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL); Assert.assertEquals(1, routes.size()); Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); @@ -219,7 +228,7 @@ public class MediaRouterManagerTest { mManager.registerCallback(mExecutor, managerCallback); mRouter2.registerCallback(mExecutor, routerCallback); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1); assertNotNull(routeToSelect); @@ -242,7 +251,7 @@ public class MediaRouterManagerTest { mRouter2.registerCallback(mExecutor, routerCallback); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); awaitOnRouteChangedManager( () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)), @@ -264,7 +273,7 @@ public class MediaRouterManagerTest { @Test public void testControlVolumeWithRouter() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL); MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); int originalVolume = volRoute.getVolume(); @@ -286,7 +295,7 @@ public class MediaRouterManagerTest { MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); mRouter2.registerCallback(mExecutor, mockCallback); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); int originalVolume = volRoute.getVolume(); @@ -309,7 +318,7 @@ public class MediaRouterManagerTest { public void testVolumeHandling() throws Exception { MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); mRouter2.registerCallback(mExecutor, mockCallback); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL); MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME); MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); @@ -321,6 +330,13 @@ public class MediaRouterManagerTest { mRouter2.unregisterCallback(mockCallback); } + @Test + public void testDefaultRoute() throws Exception { + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_LIVE_AUDIO); + + assertNotNull(routes.get(DEFAULT_ROUTE_ID)); + } + Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories) throws Exception { CountDownLatch latch = new CountDownLatch(1); MediaRouter2.Callback callback = new MediaRouter2.Callback() { @@ -417,6 +433,7 @@ public class MediaRouterManagerTest { static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) { Map<String, MediaRoute2Info> routeMap = new HashMap<>(); for (MediaRoute2Info route : routes) { + // intentionally not route.getUniqueId() for convenience. routeMap.put(route.getId(), route); } return routeMap; diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragment.java b/packages/SettingsLib/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragment.java new file mode 100644 index 000000000000..bd86d673c0d1 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragment.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2019 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.widget; + +import android.content.res.TypedArray; +import android.os.Bundle; +import android.widget.ArrayAdapter; + +import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AlertDialog.Builder; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceDialogFragmentCompat; + +import com.android.settingslib.core.instrumentation.Instrumentable; + +import java.util.ArrayList; + +/** + * {@link PreferenceDialogFragmentCompat} that updates the available options + * when {@code onListPreferenceUpdated} is called." + */ +public class UpdatableListPreferenceDialogFragment extends PreferenceDialogFragmentCompat implements + Instrumentable { + + private static final String SAVE_STATE_INDEX = "UpdatableListPreferenceDialogFragment.index"; + private static final String SAVE_STATE_ENTRIES = + "UpdatableListPreferenceDialogFragment.entries"; + private static final String SAVE_STATE_ENTRY_VALUES = + "UpdatableListPreferenceDialogFragment.entryValues"; + private static final String METRICS_CATEGORY_KEY = "metrics_category_key"; + private ArrayAdapter mAdapter; + private int mClickedDialogEntryIndex; + private ArrayList<CharSequence> mEntries; + private CharSequence[] mEntryValues; + private int mMetricsCategory = METRICS_CATEGORY_UNKNOWN; + + /** + * Creates a new instance of {@link UpdatableListPreferenceDialogFragment}. + */ + public static UpdatableListPreferenceDialogFragment newInstance( + String key, int metricsCategory) { + UpdatableListPreferenceDialogFragment fragment = + new UpdatableListPreferenceDialogFragment(); + Bundle args = new Bundle(1); + args.putString(ARG_KEY, key); + args.putInt(METRICS_CATEGORY_KEY, metricsCategory); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Bundle bundle = getArguments(); + mMetricsCategory = + bundle.getInt(METRICS_CATEGORY_KEY, METRICS_CATEGORY_UNKNOWN); + if (savedInstanceState == null) { + mEntries = new ArrayList<>(); + setPreferenceData(getListPreference()); + } else { + mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0); + mEntries = savedInstanceState.getCharSequenceArrayList(SAVE_STATE_ENTRIES); + mEntryValues = + savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex); + outState.putCharSequenceArrayList(SAVE_STATE_ENTRIES, mEntries); + outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + if (positiveResult && mClickedDialogEntryIndex >= 0) { + final ListPreference preference = getListPreference(); + final String value = mEntryValues[mClickedDialogEntryIndex].toString(); + if (preference.callChangeListener(value)) { + preference.setValue(value); + } + } + } + + @VisibleForTesting + void setAdapter(ArrayAdapter adapter) { + mAdapter = adapter; + } + + @VisibleForTesting + void setEntries(ArrayList<CharSequence> entries) { + mEntries = entries; + } + + @VisibleForTesting + ArrayAdapter getAdapter() { + return mAdapter; + } + + @VisibleForTesting + void setMetricsCategory(Bundle bundle) { + mMetricsCategory = + bundle.getInt(METRICS_CATEGORY_KEY, METRICS_CATEGORY_UNKNOWN); + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + super.onPrepareDialogBuilder(builder); + final TypedArray a = getContext().obtainStyledAttributes( + null, + com.android.internal.R.styleable.AlertDialog, + com.android.internal.R.attr.alertDialogStyle, 0); + + mAdapter = new ArrayAdapter<>( + getContext(), + a.getResourceId( + com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout, + com.android.internal.R.layout.select_dialog_singlechoice), + mEntries); + + builder.setSingleChoiceItems(mAdapter, mClickedDialogEntryIndex, + (dialog, which) -> { + mClickedDialogEntryIndex = which; + onClick(dialog, -1); + dialog.dismiss(); + }); + builder.setPositiveButton(null, null); + a.recycle(); + } + + @Override + public int getMetricsCategory() { + return mMetricsCategory; + } + + @VisibleForTesting + ListPreference getListPreference() { + return (ListPreference) getPreference(); + } + + private void setPreferenceData(ListPreference preference) { + mEntries.clear(); + mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue()); + for (CharSequence entry : preference.getEntries()) { + mEntries.add(entry); + } + mEntryValues = preference.getEntryValues(); + } + + /** + * Update new data set for list preference. + */ + public void onListPreferenceUpdated(ListPreference preference) { + if (mAdapter != null) { + setPreferenceData(preference); + mAdapter.notifyDataSetChanged(); + } + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java index 9a07ca885914..c9b066a5768e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java @@ -57,8 +57,7 @@ public class AppEntitiesHeaderControllerTest { .setIcon(mContext.getDrawable(com.android.internal.R.drawable.ic_menu)) .setTitle(TITLE) .setSummary(SUMMARY) - .setOnClickListener(v -> { - }) + .setOnClickListener(v -> { }) .build(); mController.setAppEntity(0, mAppEntityInfo); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java new file mode 100644 index 000000000000..0b3495def21f --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 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.widget; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.widget.ArrayAdapter; + +import androidx.preference.ListPreference; + +import com.android.internal.logging.nano.MetricsProto; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; + +@RunWith(RobolectricTestRunner.class) +public class UpdatableListPreferenceDialogFragmentTest { + + private static final String KEY = "Test_Key"; + @Mock + private UpdatableListPreferenceDialogFragment mUpdatableListPrefDlgFragment; + private Context mContext; + private ArrayAdapter mAdapter; + private ArrayList<CharSequence> mEntries; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + mUpdatableListPrefDlgFragment = spy(UpdatableListPreferenceDialogFragment + .newInstance(KEY, MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES)); + mEntries = spy(new ArrayList<>()); + mUpdatableListPrefDlgFragment.setEntries(mEntries); + mUpdatableListPrefDlgFragment + .setMetricsCategory(mUpdatableListPrefDlgFragment.getArguments()); + initAdapter(); + } + + private void initAdapter() { + mAdapter = spy(new ArrayAdapter<>( + mContext, + com.android.internal.R.layout.select_dialog_singlechoice, + mEntries)); + mUpdatableListPrefDlgFragment.setAdapter(mAdapter); + } + + @Test + public void getMetricsCategory() { + assertThat(mUpdatableListPrefDlgFragment.getMetricsCategory()) + .isEqualTo(MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES); + } + + @Test + public void onListPreferenceUpdated_verifyAdapterCanBeUpdate() { + assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()).isEqualTo(0); + + ListPreference listPreference = new ListPreference(mContext); + final CharSequence[] charSequences = {"Test_DEVICE_1", "Test_DEVICE_2"}; + listPreference.setEntries(charSequences); + mUpdatableListPrefDlgFragment.onListPreferenceUpdated(listPreference); + + assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()).isEqualTo(2); + } + + @Test + public void onDialogClosed_emptyPreference() { + mUpdatableListPrefDlgFragment.onDialogClosed(false); + + verify(mUpdatableListPrefDlgFragment, never()).getListPreference(); + } +} diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index c59f342d81e1..1a658f49d516 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -215,6 +215,9 @@ <!-- Permission required for CTS test - CrossProfileAppsHostSideTest --> <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/> + <!-- Permission requried for CTS test - UiModeManagerTest --> + <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index ab433d26cb3d..e9c20dbc75ad 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -369,6 +369,10 @@ <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver" android:exported="false" /> + <!-- Callback for invoking a smart action from the screenshot notification. --> + <receiver android:name=".screenshot.GlobalScreenshot$SmartActionsReceiver" + android:exported="false"/> + <!-- started from UsbDeviceSettingsManager --> <activity android:name=".usb.UsbConfirmActivity" android:exported="true" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index cce4008abe8e..99da058a2e2b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -916,6 +916,10 @@ <string name="quick_settings_ui_mode_night_label">Dark theme</string> <!-- QuickSettings: Label for the dark theme tile when enabled by battery saver. [CHAR LIMIT=40] --> <string name="quick_settings_ui_mode_night_label_battery_saver">Dark theme\nBattery saver</string> + <!-- QuickSettings: Secondary text for when the Dark Mode will be enabled at sunset. [CHAR LIMIT=20] --> + <string name="quick_settings_dark_mode_secondary_label_on_at_sunset">On at sunset</string> + <!-- QuickSettings: Secondary text for when the Dark Mode will be on until sunrise. [CHAR LIMIT=20] --> + <string name="quick_settings_dark_mode_secondary_label_until_sunrise">Until sunrise</string> <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] --> <string name="quick_settings_nfc_label">NFC</string> diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 1a0690c1a273..a616484a3b21 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -163,10 +163,6 @@ public class Dependency { */ private static final String BG_LOOPER_NAME = "background_looper"; /** - * Key for getting a background Handler for background work. - */ - private static final String BG_HANDLER_NAME = "background_handler"; - /** * Key for getting a Handler for receiving time tick broadcasts on. */ public static final String TIME_TICK_HANDLER_NAME = "time_tick_handler"; @@ -195,10 +191,6 @@ public class Dependency { */ public static final DependencyKey<Looper> MAIN_LOOPER = new DependencyKey<>(MAIN_LOOPER_NAME); /** - * Key for getting a background Handler for background work. - */ - public static final DependencyKey<Handler> BG_HANDLER = new DependencyKey<>(BG_HANDLER_NAME); - /** * Key for getting a Handler for receiving time tick broadcasts on. */ public static final DependencyKey<Handler> TIME_TICK_HANDLER = @@ -347,7 +339,6 @@ public class Dependency { // on imports. mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get); mProviders.put(BG_LOOPER, mBgLooper::get); - mProviders.put(BG_HANDLER, mBgHandler::get); mProviders.put(MAIN_LOOPER, mMainLooper::get); mProviders.put(MAIN_HANDLER, mMainHandler::get); mProviders.put(ActivityStarter.class, mActivityStarter::get); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 0d400fef6061..617dbdfe3fcc 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -45,6 +45,8 @@ import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.KeyguardStateController; +import java.util.concurrent.Executor; + import dagger.Module; import dagger.Provides; @@ -124,7 +126,9 @@ public class SystemUIFactory { * This method is overridden in vendor specific implementation of Sys UI. */ public ScreenshotNotificationSmartActionsProvider - createScreenshotNotificationSmartActionsProvider() { + createScreenshotNotificationSmartActionsProvider(Context context, + Executor executor, + Handler uiHandler) { return new ScreenshotNotificationSmartActionsProvider(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java index 0d4cc0170be9..add5f08d7d44 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java @@ -36,6 +36,7 @@ import android.service.dreams.IDreamManager; import android.view.IWindowManager; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.view.accessibility.AccessibilityManager; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.LatencyTracker; @@ -54,6 +55,11 @@ import dagger.Provides; */ @Module public class SystemServicesModule { + @Provides + @Singleton + static AccessibilityManager provideAccessibilityManager(Context context) { + return context.getSystemService(AccessibilityManager.class); + } @Singleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index dd0ea5ef17f4..dc9a2ce1beef 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -21,7 +21,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.provider.Settings; import android.service.quicksettings.Tile; -import android.widget.Switch; +import android.text.TextUtils; import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.R; @@ -79,24 +79,33 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements return; } boolean newState = !mState.value; - mUiModeManager.setNightMode(newState ? UiModeManager.MODE_NIGHT_YES - : UiModeManager.MODE_NIGHT_NO); + mUiModeManager.setNightModeActivated(newState); refreshState(newState); } @Override protected void handleUpdateState(BooleanState state, Object arg) { + int uiMode = mUiModeManager.getNightMode(); boolean powerSave = mBatteryController.isPowerSave(); + boolean isAuto = uiMode == UiModeManager.MODE_NIGHT_AUTO; boolean nightMode = (mContext.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + if (isAuto) { + state.secondaryLabel = mContext.getResources().getString(nightMode + ? R.string.quick_settings_dark_mode_secondary_label_until_sunrise + : R.string.quick_settings_dark_mode_secondary_label_on_at_sunset); + } else { + state.secondaryLabel = null; + } state.value = nightMode; state.label = mContext.getString(powerSave ? R.string.quick_settings_ui_mode_night_label_battery_saver : R.string.quick_settings_ui_mode_night_label); - state.contentDescription = state.label; state.icon = mIcon; - state.expandedAccessibilityClassName = Switch.class.getName(); + state.contentDescription = TextUtils.isEmpty(state.secondaryLabel) + ? state.label + : TextUtils.concat(state.label, ", ", state.secondaryLabel); if (powerSave) { state.state = Tile.STATE_UNAVAILABLE; } else { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index e790c1d071ce..66cd91996cea 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -75,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.R; import com.android.systemui.SystemUI; +import com.android.systemui.SystemUIFactory; import com.android.systemui.dagger.qualifiers.MainResources; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.phone.StatusBar; @@ -126,8 +127,17 @@ public class GlobalScreenshot { } } - static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id"; + // These strings are used for communicating the action invoked to + // ScreenshotNotificationSmartActionsProvider. + static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type"; + static final String EXTRA_ID = "android:screenshot_id"; + static final String ACTION_TYPE_DELETE = "Delete"; + static final String ACTION_TYPE_SHARE = "Share"; + static final String ACTION_TYPE_EDIT = "Edit"; + static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled"; static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent"; + + static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id"; static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification"; static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip"; @@ -689,9 +699,9 @@ public class GlobalScreenshot { } @VisibleForTesting - static CompletableFuture<List<Notification.Action>> getSmartActionsFuture(Context context, + static CompletableFuture<List<Notification.Action>> getSmartActionsFuture(String screenshotId, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, - Handler handler, boolean smartActionsEnabled, boolean isManagedProfile) { + boolean smartActionsEnabled, boolean isManagedProfile) { if (!smartActionsEnabled) { Slog.i(TAG, "Screenshot Intelligence not enabled, returning empty list."); return CompletableFuture.completedFuture(Collections.emptyList()); @@ -705,6 +715,7 @@ public class GlobalScreenshot { Slog.d(TAG, "Screenshot from a managed profile: " + isManagedProfile); CompletableFuture<List<Notification.Action>> smartActionsFuture; + long startTimeMs = SystemClock.uptimeMillis(); try { ActivityManager.RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); @@ -712,34 +723,74 @@ public class GlobalScreenshot { (runningTask != null && runningTask.topActivity != null) ? runningTask.topActivity : new ComponentName("", ""); - smartActionsFuture = smartActionsProvider.getActions(image, context, - THREAD_POOL_EXECUTOR, - handler, + smartActionsFuture = smartActionsProvider.getActions(screenshotId, image, componentName, isManagedProfile); } catch (Throwable e) { + long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList()); Slog.e(TAG, "Failed to get future for screenshot notification smart actions.", e); + notifyScreenshotOp(screenshotId, smartActionsProvider, + ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS, + ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR, + waitTimeMs); } return smartActionsFuture; } @VisibleForTesting - static List<Notification.Action> getSmartActions( - CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs) { + static List<Notification.Action> getSmartActions(String screenshotId, + CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs, + ScreenshotNotificationSmartActionsProvider smartActionsProvider) { + long startTimeMs = SystemClock.uptimeMillis(); try { - long startTimeMs = SystemClock.uptimeMillis(); List<Notification.Action> actions = smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS); + long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; Slog.d(TAG, String.format("Wait time for smart actions: %d ms", - SystemClock.uptimeMillis() - startTimeMs)); + waitTimeMs)); + notifyScreenshotOp(screenshotId, smartActionsProvider, + ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, + ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS, + waitTimeMs); return actions; } catch (Throwable e) { - Slog.e(TAG, "Failed to obtain screenshot notification smart actions.", e); + long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; + Slog.d(TAG, "Failed to obtain screenshot notification smart actions.", e); + ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status = + (e instanceof TimeoutException) + ? ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT + : ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR; + notifyScreenshotOp(screenshotId, smartActionsProvider, + ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, + status, waitTimeMs); return Collections.emptyList(); } } + static void notifyScreenshotOp(String screenshotId, + ScreenshotNotificationSmartActionsProvider smartActionsProvider, + ScreenshotNotificationSmartActionsProvider.ScreenshotOp op, + ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs) { + try { + smartActionsProvider.notifyOp(screenshotId, op, status, durationMs); + } catch (Throwable e) { + Slog.e(TAG, "Error in notifyScreenshotOp: ", e); + } + } + + static void notifyScreenshotAction(Context context, String screenshotId, String action, + boolean isSmartAction) { + try { + ScreenshotNotificationSmartActionsProvider provider = + SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( + context, THREAD_POOL_EXECUTOR, new Handler()); + provider.notifyAction(screenshotId, action, isSmartAction); + } catch (Throwable e) { + Slog.e(TAG, "Error in notifyScreenshotAction: ", e); + } + } + /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). @@ -783,6 +834,13 @@ public class GlobalScreenshot { } else { startActivityRunnable.run(); } + + if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { + String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) ? ACTION_TYPE_EDIT + : ACTION_TYPE_SHARE; + notifyScreenshotAction(context, intent.getStringExtra(EXTRA_ID), + actionType, false); + } } } @@ -813,6 +871,29 @@ public class GlobalScreenshot { // And delete the image from the media store final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); new DeleteImageInBackgroundTask(context).execute(uri); + if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { + notifyScreenshotAction(context, intent.getStringExtra(EXTRA_ID), + ACTION_TYPE_DELETE, + false); + } + } + } + + /** + * Executes the smart action tapped by the user in the notification. + */ + public static class SmartActionsReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); + ActivityOptions opts = ActivityOptions.makeBasic(); + context.startActivityAsUser(actionIntent.getIntent(), opts.toBundle(), + UserHandle.CURRENT); + + Slog.d(TAG, "Screenshot notification smart action is invoked."); + notifyScreenshotAction(context, intent.getStringExtra(EXTRA_ID), + intent.getStringExtra(EXTRA_ACTION_TYPE), + true); } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index e9dbe02371d5..5e5cf743b468 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -38,6 +38,7 @@ import android.media.ExifInterface; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; +import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.ParcelFileDescriptor; @@ -50,6 +51,7 @@ import android.provider.MediaStore; import android.text.TextUtils; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.messages.nano.SystemMessageProto; import com.android.systemui.R; @@ -69,9 +71,12 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.Random; +import java.util.UUID; import java.util.concurrent.CompletableFuture; /** @@ -81,6 +86,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { private static final String TAG = "SaveImageInBackgroundTask"; private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png"; + private static final String SCREENSHOT_ID_TEMPLATE = "Screenshot_%s"; private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"; private final GlobalScreenshot.SaveImageInBackgroundData mParams; @@ -91,8 +97,10 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { private final Notification.BigPictureStyle mNotificationStyle; private final int mImageWidth; private final int mImageHeight; - private final Handler mHandler; private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider; + private final String mScreenshotId; + private final boolean mSmartActionsEnabled; + private final Random mRandom = new Random(); SaveImageInBackgroundTask(Context context, GlobalScreenshot.SaveImageInBackgroundData data, NotificationManager nManager) { @@ -103,11 +111,20 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mImageTime = System.currentTimeMillis(); String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime)); mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate); + mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, UUID.randomUUID()); // Initialize screenshot notification smart actions provider. - mHandler = new Handler(); - mSmartActionsProvider = - SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider(); + mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, false); + if (mSmartActionsEnabled) { + mSmartActionsProvider = + SystemUIFactory.getInstance() + .createScreenshotNotificationSmartActionsProvider( + context, THREAD_POOL_EXECUTOR, new Handler()); + } else { + // If smart actions is not enabled use empty implementation. + mSmartActionsProvider = new ScreenshotNotificationSmartActionsProvider(); + } // Create the large notification icon mImageWidth = data.image.getWidth(); @@ -201,6 +218,38 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { return info.isManagedProfile(); } + private List<Notification.Action> buildSmartActions( + List<Notification.Action> actions, Context context) { + List<Notification.Action> broadcastActions = new ArrayList<>(); + for (Notification.Action action : actions) { + // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver} + // for logging smart actions. + Bundle extras = action.getExtras(); + String actionType = extras.getString( + ScreenshotNotificationSmartActionsProvider.ACTION_TYPE, + ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE); + Intent intent = new Intent(context, + GlobalScreenshot.SmartActionsReceiver.class).putExtra( + GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent); + addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled); + PendingIntent broadcastIntent = PendingIntent.getBroadcast(context, + mRandom.nextInt(), + intent, + PendingIntent.FLAG_CANCEL_CURRENT); + broadcastActions.add(new Notification.Action.Builder(action.getIcon(), action.title, + broadcastIntent).setContextual(true).addExtras(extras).build()); + } + return broadcastActions; + } + + private static void addIntentExtras(String screenshotId, Intent intent, String actionType, + boolean smartActionsEnabled) { + intent + .putExtra(GlobalScreenshot.EXTRA_ACTION_TYPE, actionType) + .putExtra(GlobalScreenshot.EXTRA_ID, screenshotId) + .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled); + } + /** * Generates a new hardware bitmap with specified values, copying the content from the * passed in bitmap. @@ -227,16 +276,13 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { Context context = mParams.context; Bitmap image = mParams.image; - boolean smartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true); - CompletableFuture<List<Notification.Action>> - smartActionsFuture = GlobalScreenshot.getSmartActionsFuture( - context, image, mSmartActionsProvider, mHandler, smartActionsEnabled, - isManagedProfile(context)); - Resources r = context.getResources(); try { + CompletableFuture<List<Notification.Action>> smartActionsFuture = + GlobalScreenshot.getSmartActionsFuture(mScreenshotId, image, + mSmartActionsProvider, mSmartActionsEnabled, isManagedProfile(context)); + // Save the screenshot to the MediaStore final MediaStore.PendingParams params = new MediaStore.PendingParams( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png"); @@ -289,104 +335,11 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { IoUtils.closeQuietly(session); } - // Note: Both the share and edit actions are proxied through ActionProxyReceiver in - // order to do some common work like dismissing the keyguard and sending - // closeSystemWindows - - // Create a share intent, this will always go through the chooser activity first - // which should not trigger auto-enter PiP - String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); - String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); - Intent sharingIntent = new Intent(Intent.ACTION_SEND); - sharingIntent.setType("image/png"); - sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); - // Include URI in ClipData also, so that grantPermission picks it up. - // We don't use setData here because some apps interpret this as "to:". - ClipData clipdata = new ClipData(new ClipDescription("content", - new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), - new ClipData.Item(uri)); - sharingIntent.setClipData(clipdata); - sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); - sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Make sure pending intents for the system user are still unique across users - // by setting the (otherwise unused) request code to the current user id. - int requestCode = context.getUserId(); - - PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, - chooserAction.getIntentSender()) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Create a share action for the notification - PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) - .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, sharingChooserIntent) - .putExtra(GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP, true) - .setAction(Intent.ACTION_SEND), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); - Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_share, - r.getString(com.android.internal.R.string.share), shareAction); - mNotificationBuilder.addAction(shareActionBuilder.build()); - - // Create an edit intent, if a specific package is provided as the editor, then - // launch that directly - String editorPackage = context.getString(R.string.config_screenshotEditor); - Intent editIntent = new Intent(Intent.ACTION_EDIT); - if (!TextUtils.isEmpty(editorPackage)) { - editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); - } - editIntent.setType("image/png"); - editIntent.setData(uri); - editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - - // Create a edit action - PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) - .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, editIntent) - .putExtra(GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION, - editIntent.getComponent() != null) - .setAction(Intent.ACTION_EDIT), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); - Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_edit, - r.getString(com.android.internal.R.string.screenshot_edit), editAction); - mNotificationBuilder.addAction(editActionBuilder.build()); - if (editAction != null && mParams.onEditReady != null) { - mParams.onEditReady.apply(editAction); - } - - // Create a delete action for the notification - PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) - .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_delete, - r.getString(com.android.internal.R.string.delete), deleteAction); - mNotificationBuilder.addAction(deleteActionBuilder.build()); + populateNotificationActions(context, r, uri, smartActionsFuture, mNotificationBuilder); mParams.imageUri = uri; mParams.image = null; mParams.errorMsgResId = 0; - - if (smartActionsEnabled) { - int timeoutMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags - .SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS, - 1000); - List<Notification.Action> smartActions = GlobalScreenshot.getSmartActions( - smartActionsFuture, - timeoutMs); - for (Notification.Action action : smartActions) { - mNotificationBuilder.addAction(action); - } - } } catch (Exception e) { // IOException/UnsupportedOperationException may be thrown if external storage is // not mounted @@ -403,6 +356,115 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { return null; } + @VisibleForTesting + void populateNotificationActions(Context context, Resources r, Uri uri, + CompletableFuture<List<Notification.Action>> smartActionsFuture, + Notification.Builder notificationBuilder) { + // Note: Both the share and edit actions are proxied through ActionProxyReceiver in + // order to do some common work like dismissing the keyguard and sending + // closeSystemWindows + + // Create a share intent, this will always go through the chooser activity first + // which should not trigger auto-enter PiP + String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); + String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); + Intent sharingIntent = new Intent(Intent.ACTION_SEND); + sharingIntent.setType("image/png"); + sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); + // Include URI in ClipData also, so that grantPermission picks it up. + // We don't use setData here because some apps interpret this as "to:". + ClipData clipdata = new ClipData(new ClipDescription("content", + new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), + new ClipData.Item(uri)); + sharingIntent.setClipData(clipdata); + sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Make sure pending intents for the system user are still unique across users + // by setting the (otherwise unused) request code to the current user id. + int requestCode = context.getUserId(); + + PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode, + new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, + chooserAction.getIntentSender()) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Create a share action for the notification + PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, sharingChooserIntent) + .putExtra(GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP, true) + .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) + .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, + mSmartActionsEnabled) + .setAction(Intent.ACTION_SEND), + PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_share, + r.getString(com.android.internal.R.string.share), shareAction); + notificationBuilder.addAction(shareActionBuilder.build()); + + // Create an edit intent, if a specific package is provided as the editor, then + // launch that directly + String editorPackage = context.getString(R.string.config_screenshotEditor); + Intent editIntent = new Intent(Intent.ACTION_EDIT); + if (!TextUtils.isEmpty(editorPackage)) { + editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); + } + editIntent.setType("image/png"); + editIntent.setData(uri); + editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + + // Create a edit action + PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, editIntent) + .putExtra(GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION, + editIntent.getComponent() != null) + .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) + .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, + mSmartActionsEnabled) + .setAction(Intent.ACTION_EDIT), + PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_edit, + r.getString(com.android.internal.R.string.screenshot_edit), editAction); + notificationBuilder.addAction(editActionBuilder.build()); + if (editAction != null && mParams.onEditReady != null) { + mParams.onEditReady.apply(editAction); + } + + // Create a delete action for the notification + PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, + new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) + .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()) + .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) + .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, + mSmartActionsEnabled), + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_delete, + r.getString(com.android.internal.R.string.delete), deleteAction); + notificationBuilder.addAction(deleteActionBuilder.build()); + + if (mSmartActionsEnabled) { + int timeoutMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags + .SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS, + 1000); + List<Notification.Action> smartActions = buildSmartActions( + GlobalScreenshot.getSmartActions(mScreenshotId, smartActionsFuture, + timeoutMs, mSmartActionsProvider), context); + for (Notification.Action action : smartActions) { + notificationBuilder.addAction(action); + } + } + } + @Override protected void onPostExecute(Void params) { if (mParams.errorMsgResId != 0) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java index fa23bf7d5bde..b6f5447d2867 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java @@ -18,41 +18,84 @@ package com.android.systemui.screenshot; import android.app.Notification; import android.content.ComponentName; -import android.content.Context; import android.graphics.Bitmap; -import android.os.Handler; import android.util.Log; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; /** * This class can be overridden by a vendor-specific sys UI implementation, * in order to provide smart actions in the screenshot notification. */ public class ScreenshotNotificationSmartActionsProvider { + /* Key provided in the notification action to get the type of smart action. */ + public static final String ACTION_TYPE = "action_type"; + public static final String DEFAULT_ACTION_TYPE = "Smart Action"; + + /* Define phases of screenshot execution. */ + protected enum ScreenshotOp { + OP_UNKNOWN, + RETRIEVE_SMART_ACTIONS, + REQUEST_SMART_ACTIONS, + WAIT_FOR_SMART_ACTIONS + } + + /* Enum to report success or failure for screenshot execution phases. */ + protected enum ScreenshotOpStatus { + OP_STATUS_UNKNOWN, + SUCCESS, + ERROR, + TIMEOUT + } + private static final String TAG = "ScreenshotActions"; /** * Default implementation that returns an empty list. * This method is overridden in vendor-specific Sys UI implementation. * + * @param screenshotId A generated random unique id for the screenshot. * @param bitmap The bitmap of the screenshot. The bitmap config must be {@link * HARDWARE}. - * @param context The current app {@link Context}. - * @param executor A {@link Executor} that can be used to execute tasks in parallel. - * @param handler A {@link Handler} to possibly run UI-thread code. * @param componentName Contains package and activity class names where the screenshot was * taken. This is used as an additional signal to generate and rank more * relevant actions. * @param isManagedProfile The screenshot was taken for a work profile app. */ - public CompletableFuture<List<Notification.Action>> getActions(Bitmap bitmap, Context context, - Executor executor, Handler handler, ComponentName componentName, + public CompletableFuture<List<Notification.Action>> getActions( + String screenshotId, + Bitmap bitmap, + ComponentName componentName, boolean isManagedProfile) { Log.d(TAG, "Returning empty smart action list."); return CompletableFuture.completedFuture(Collections.emptyList()); } + + /** + * Notify exceptions and latency encountered during generating smart actions. + * This method is overridden in vendor-specific Sys UI implementation. + * + * @param screenshotId Unique id of the screenshot. + * @param op screenshot execution phase defined in {@link ScreenshotOp} + * @param status {@link ScreenshotOpStatus} to report success or failure. + * @param durationMs latency experienced in different phases of screenshots. + */ + public void notifyOp(String screenshotId, ScreenshotOp op, ScreenshotOpStatus status, + long durationMs) { + Log.d(TAG, "Return without notify."); + } + + /** + * Notify screenshot notification action invoked. + * This method is overridden in vendor-specific Sys UI implementation. + * + * @param screenshotId Unique id of the screenshot. + * @param action type of notification action invoked. + * @param isSmartAction whether action invoked was a smart action. + */ + public void notifyAction(String screenshotId, String action, boolean isSmartAction) { + Log.d(TAG, "Return without notify."); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 021e7e15c7f6..89aad8f37b8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -333,7 +333,6 @@ public class NotificationLockscreenUserManagerImpl implements } private boolean hideSilentNotificationsOnLockscreen() { - // TODO(b/140058091) return whitelistIpcs(() -> Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 77c0a460f3b6..5a5f9e901514 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; @@ -41,6 +42,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; +import com.android.systemui.dagger.qualifiers.MainHandler; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLifetimeExtender; @@ -101,16 +103,18 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx protected String mKeyToRemoveOnGutsClosed; private final Lazy<StatusBar> mStatusBarLazy; + private final Handler mMainHandler; private Runnable mOpenRunnable; @Inject public NotificationGutsManager(Context context, VisualStabilityManager visualStabilityManager, - Lazy<StatusBar> statusBarLazy) { + Lazy<StatusBar> statusBarLazy, @MainHandler Handler mainHandler, + AccessibilityManager accessibilityManager) { mContext = context; mVisualStabilityManager = visualStabilityManager; mStatusBarLazy = statusBarLazy; - mAccessibilityManager = (AccessibilityManager) - mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); + mMainHandler = mainHandler; + mAccessibilityManager = accessibilityManager; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -389,7 +393,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx .setLeaveOpenOnKeyguardHide(true); } - Runnable r = () -> Dependency.get(Dependency.MAIN_HANDLER).post( + Runnable r = () -> mMainHandler.post( () -> openGutsInternal(view, x, y, menuItem)); mStatusBarLazy.get().executeRunnableDismissingKeyguard( diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt index 098521fbda51..20148e11489a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt @@ -110,7 +110,6 @@ class PrivacyItemControllerTest : SysuiTestCase() { handler = Handler(testableLooper.looper) appOpsController = mDependency.injectMockDependency(AppOpsController::class.java) - mDependency.injectTestDependency(Dependency.BG_HANDLER, handler) mDependency.injectTestDependency(Dependency.MAIN_HANDLER, handler) mContext.addMockSystemService(UserManager::class.java, userManager) mContext.getOrCreateTestableResources().addOverride(R.string.device_services, diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 99850e7c922e..3f32c66b2d03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -16,8 +16,12 @@ package com.android.systemui.screenshot; +import static android.content.Context.NOTIFICATION_SERVICE; + import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -25,14 +29,20 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; +import android.app.NotificationManager; +import android.content.Intent; import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.NotificationChannels; import org.junit.Assert; import org.junit.Before; @@ -70,12 +80,12 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); ScreenshotNotificationSmartActionsProvider smartActionsProvider = mock( ScreenshotNotificationSmartActionsProvider.class); - when(smartActionsProvider.getActions(any(), any(), any(), any(), any(), + when(smartActionsProvider.getActions(any(), any(), any(), eq(false))).thenThrow( RuntimeException.class); CompletableFuture<List<Notification.Action>> smartActionsFuture = - GlobalScreenshot.getSmartActionsFuture(mContext, bitmap, - smartActionsProvider, mHandler, true, false); + GlobalScreenshot.getSmartActionsFuture("", bitmap, + smartActionsProvider, true, false); Assert.assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); Assert.assertEquals(Collections.emptyList(), smartActions); @@ -92,10 +102,19 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS)).thenThrow( RuntimeException.class); List<Notification.Action> actions = GlobalScreenshot.getSmartActions( - smartActionsFuture, timeoutMs); + "", smartActionsFuture, timeoutMs, mSmartActionsProvider); Assert.assertEquals(Collections.emptyList(), actions); } + // Tests any exception thrown in notifying feedback does not affect regular screenshot flow. + @Test + public void testExceptionHandlingInNotifyingFeedback() + throws Exception { + doThrow(RuntimeException.class).when(mSmartActionsProvider).notifyOp(any(), any(), any(), + anyLong()); + GlobalScreenshot.notifyScreenshotOp(null, mSmartActionsProvider, null, null, -1); + } + // Tests for a non-hardware bitmap, ScreenshotNotificationSmartActionsProvider is never invoked // and a completed future is returned. @Test @@ -104,9 +123,9 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.RGB_565); CompletableFuture<List<Notification.Action>> smartActionsFuture = - GlobalScreenshot.getSmartActionsFuture(mContext, bitmap, - mSmartActionsProvider, mHandler, true, true); - verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), any(), + GlobalScreenshot.getSmartActionsFuture("", bitmap, + mSmartActionsProvider, true, true); + verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), eq(false)); Assert.assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); @@ -118,10 +137,10 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { public void testScreenshotNotificationSmartActionsProviderInvokedOnce() { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); - GlobalScreenshot.getSmartActionsFuture(mContext, bitmap, mSmartActionsProvider, - mHandler, true, true); + GlobalScreenshot.getSmartActionsFuture("", bitmap, mSmartActionsProvider, + true, true); verify(mSmartActionsProvider, times(1)) - .getActions(any(), any(), any(), any(), any(), eq(true)); + .getActions(any(), any(), any(), eq(true)); } // Tests for a hardware bitmap, a completed future is returned. @@ -131,13 +150,65 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); ScreenshotNotificationSmartActionsProvider actionsProvider = - SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider(); + SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( + mContext, null, mHandler); CompletableFuture<List<Notification.Action>> smartActionsFuture = - GlobalScreenshot.getSmartActionsFuture(mContext, bitmap, + GlobalScreenshot.getSmartActionsFuture("", bitmap, actionsProvider, - mHandler, true, true); + true, true); Assert.assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); Assert.assertEquals(smartActions.size(), 0); } + + // Tests for notification action extras. + @Test + public void testNotificationActionExtras() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + NotificationManager notificationManager = + (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE); + GlobalScreenshot.SaveImageInBackgroundData + data = new GlobalScreenshot.SaveImageInBackgroundData(); + data.context = mContext; + data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + data.iconSize = 10; + data.finisher = null; + data.onEditReady = null; + data.previewWidth = 10; + data.previewheight = 10; + SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data, + notificationManager); + Notification.Builder notificationBuilder = new Notification.Builder(mContext, + NotificationChannels.SCREENSHOTS_HEADSUP); + task.populateNotificationActions(mContext, mContext.getResources(), + Uri.parse("Screenshot_123.png"), + CompletableFuture.completedFuture(Collections.emptyList()), notificationBuilder); + + Notification notification = notificationBuilder.build(); + Assert.assertEquals(notification.actions.length, 3); + boolean isShareFound = false; + boolean isEditFound = false; + boolean isDeleteFound = false; + for (Notification.Action action : notification.actions) { + Intent intent = action.actionIntent.getIntent(); + Assert.assertNotNull(intent); + Bundle bundle = intent.getExtras(); + Assert.assertTrue(bundle.containsKey(GlobalScreenshot.EXTRA_ID)); + Assert.assertTrue(bundle.containsKey(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED)); + + if (action.title.equals(GlobalScreenshot.ACTION_TYPE_DELETE)) { + isDeleteFound = intent.getAction() == null; + } else if (action.title.equals(GlobalScreenshot.ACTION_TYPE_EDIT)) { + isEditFound = Intent.ACTION_EDIT.equals(intent.getAction()); + } else if (action.title.equals(GlobalScreenshot.ACTION_TYPE_SHARE)) { + isShareFound = Intent.ACTION_SEND.equals(intent.getAction()); + } + } + + Assert.assertTrue(isEditFound); + Assert.assertTrue(isDeleteFound); + Assert.assertTrue(isShareFound); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 749dae5c9c8a..4b3249d788d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -56,6 +56,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArraySet; import android.view.View; +import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; @@ -110,6 +111,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private OnSettingsClickListener mOnSettingsClickListener; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private StatusBar mStatusBar; + @Mock private AccessibilityManager mAccessibilityManager; @Before public void setUp() { @@ -122,9 +124,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mDependency.injectMockDependency(NotificationLockscreenUserManager.class); mHandler = Handler.createAsync(mTestableLooper.getLooper()); mHelper = new NotificationTestHelper(mContext, mDependency); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager, - () -> mStatusBar); + () -> mStatusBar, mHandler, mAccessibilityManager); mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index cf0e3b2ddda7..ca9b1681bacc 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -251,7 +251,7 @@ public class TetheringConfiguration { /** Check whether dun is required. */ public static boolean checkDunRequired(Context ctx, int id) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); - return (tm != null) ? tm.isTetherApnRequired(id) : false; + return (tm != null) ? tm.isTetheringApnRequired(id) : false; } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 9c65c0deed07..30bff3560955 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -145,7 +145,7 @@ public class TetheringConfigurationTest { @Test public void testDunFromTelephonyManagerMeansDun() { - when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(true); + when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(true); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -169,7 +169,7 @@ public class TetheringConfigurationTest { @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { - when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -212,7 +212,7 @@ public class TetheringConfigurationTest { @Test public void testNoDefinedUpstreamTypesAddsEthernet() { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); - when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -235,7 +235,7 @@ public class TetheringConfigurationTest { public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -253,7 +253,7 @@ public class TetheringConfigurationTest { public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { when(mResources.getIntArray(config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 950fa8d4038a..5eaa80a5143b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -47,6 +47,7 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; @@ -62,6 +63,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import com.android.internal.annotations.GuardedBy; +import com.android.internal.compat.IPlatformCompat; import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; @@ -95,6 +97,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private final AccessibilityWindowManager mA11yWindowManager; private final DisplayManager mDisplayManager; private final PowerManager mPowerManager; + private final IPlatformCompat mIPlatformCompat; // Handler for scheduling method invocations on the main thread. public final InvocationHandler mInvocationHandler; @@ -228,6 +231,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ mA11yWindowManager = a11yWindowManager; mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mIPlatformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mEventDispatchHandler = new Handler(mainHandler.getLooper()) { @Override public void handleMessage(Message message) { @@ -336,7 +341,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ // configurable properties. AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; if (oldInfo != null) { - oldInfo.updateDynamicallyConfigurableProperties(info); + oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info); setDynamicallyConfigurableProperties(oldInfo); } else { setDynamicallyConfigurableProperties(info); diff --git a/services/core/Android.bp b/services/core/Android.bp index c6bc1068da39..b8caefd45135 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -92,6 +92,7 @@ java_library_static { "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", "app-compat-annotations", + "vintf-vibrator-java", ], required: [ @@ -111,13 +112,16 @@ java_library_static { "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.oemlock-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", - "android.hardware.vibrator-V1.4-java", "android.hardware.configstore-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hidl.manager-V1.2-java", "dnsresolver_aidl_interface-V2-java", "netd_event_listener_interface-java", ], + + plugins: [ + "compat-changeid-annotation-processor", + ], } java_genrule { diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index 5522396ac3e2..94793d0fb717 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -14,6 +14,15 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] + }, + { + "name": "CtsLocationFineTestCases" + }, + { + "name": "CtsLocationCoarseTestCases" + }, + { + "name": "CtsLocationNoneTestCases" } ] } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index a51746767f0f..b5702541432a 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.IntRange; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -41,6 +42,7 @@ import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -52,9 +54,10 @@ import android.provider.Settings.Secure; import android.service.dreams.Sandman; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; +import android.util.ArraySet; import android.util.Slog; - import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.DisableCarModeActivity; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -62,9 +65,15 @@ import com.android.internal.util.DumpUtils; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; +import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static android.content.Intent.ACTION_SCREEN_OFF; final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -79,7 +88,12 @@ final class UiModeManagerService extends SystemService { private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mNightMode = UiModeManager.MODE_NIGHT_NO; + // we use the override auto mode + // for example: force night mode off in the night time while in auto mode + private int mNightModeOverride = mNightMode; + protected static final String OVERRIDE_NIGHT_MODE = Secure.UI_NIGHT_MODE + "_override"; + private Map<Integer, String> mCarModePackagePriority = new HashMap<>(); private boolean mCarModeEnabled = false; private boolean mCharging = false; private boolean mPowerSave = false; @@ -112,6 +126,7 @@ final class UiModeManagerService extends SystemService { private TwilightManager mTwilightManager; private NotificationManager mNotificationManager; private StatusBarManager mStatusBarManager; + private WindowManagerInternal mWindowManager; private PowerManager.WakeLock mWakeLock; @@ -121,6 +136,17 @@ final class UiModeManagerService extends SystemService { super(context); } + @VisibleForTesting + protected UiModeManagerService(Context context, WindowManagerInternal wm, + PowerManager.WakeLock wl, TwilightManager tm, + boolean setupWizardComplete) { + super(context); + mWindowManager = wm; + mWakeLock = wl; + mTwilightManager = tm; + mSetupWizardComplete = setupWizardComplete; + } + private static Intent buildHomeIntent(String category) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(category); @@ -182,8 +208,23 @@ final class UiModeManagerService extends SystemService { public void onTwilightStateChanged(@Nullable TwilightState state) { synchronized (mLock) { if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { - updateComputedNightModeLocked(); - updateLocked(0, 0); + final IntentFilter intentFilter = + new IntentFilter(ACTION_SCREEN_OFF); + getContext().registerReceiver(mOnScreenOffHandler, intentFilter); + } + } + } + }; + + private final BroadcastReceiver mOnScreenOffHandler = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + updateLocked(0, 0); + try { + getContext().unregisterReceiver(mOnScreenOffHandler); + } catch (IllegalArgumentException e) { + // we ignore this exception if the receiver is unregistered already. } } } @@ -222,6 +263,8 @@ final class UiModeManagerService extends SystemService { public void onChange(boolean selfChange, Uri uri) { int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, mNightMode, 0); + mode = mode == UiModeManager.MODE_NIGHT_AUTO + ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO; SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); } }; @@ -240,6 +283,7 @@ final class UiModeManagerService extends SystemService { final PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + mWindowManager = LocalServices.getService(WindowManagerInternal.class); // If setup isn't complete for this user listen for completion so we can unblock // being able to send a night mode configuration change event @@ -306,6 +350,16 @@ final class UiModeManagerService extends SystemService { false, mDarkThemeObserver, 0); } + @VisibleForTesting + protected IUiModeManager getService() { + return mService; + } + + @VisibleForTesting + protected Configuration getConfiguration() { + return mConfiguration; + } + // Records whether setup wizard has happened or not and adds an observer for this user if not. private void verifySetupWizardCompleted() { final Context context = getContext(); @@ -340,8 +394,11 @@ final class UiModeManagerService extends SystemService { if (mSetupWizardComplete) { mNightMode = Secure.getIntForUser(context.getContentResolver(), Secure.UI_NIGHT_MODE, defaultNightMode, userId); + mNightModeOverride = Secure.getIntForUser(context.getContentResolver(), + OVERRIDE_NIGHT_MODE, defaultNightMode, userId); } else { mNightMode = defaultNightMode; + mNightModeOverride = defaultNightMode; } return oldNightMode != mNightMode; @@ -349,15 +406,25 @@ final class UiModeManagerService extends SystemService { private final IUiModeManager.Stub mService = new IUiModeManager.Stub() { @Override - public void enableCarMode(int flags) { + public void enableCarMode(@UiModeManager.EnableCarMode int flags, + @IntRange(from = 0) int priority, String callingPackage) { if (isUiModeLocked()) { Slog.e(TAG, "enableCarMode while UI mode is locked"); return; } + + if (priority != UiModeManager.DEFAULT_PRIORITY + && getContext().checkCallingOrSelfPermission( + android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Enabling car mode with a priority requires " + + "permission ENTER_CAR_MODE_PRIORITIZED"); + } + final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setCarModeLocked(true, flags); + setCarModeLocked(true, flags, priority, callingPackage); if (mSystemReady) { updateLocked(flags, 0); } @@ -367,16 +434,49 @@ final class UiModeManagerService extends SystemService { } } + /** + * This method is only kept around for the time being; the AIDL has an UnsupportedAppUsage + * tag which means this method is technically considered part of the greylist "API". + * @param flags + */ + @Override + public void disableCarMode(@UiModeManager.DisableCarMode int flags) { + disableCarModeByCallingPackage(flags, null /* callingPackage */); + } + + /** + * Handles requests to disable car mode. + * @param flags Disable car mode flags + * @param callingPackage + */ @Override - public void disableCarMode(int flags) { + public void disableCarModeByCallingPackage(@UiModeManager.DisableCarMode int flags, + String callingPackage) { if (isUiModeLocked()) { Slog.e(TAG, "disableCarMode while UI mode is locked"); return; } + + // If the caller is the system, we will allow the DISABLE_CAR_MODE_ALL_PRIORITIES car + // mode flag to be specified; this is so that the user can disable car mode at all + // priorities using the persistent notification. + boolean isSystemCaller = Binder.getCallingUid() == Process.SYSTEM_UID; + final int carModeFlags = + isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES; + final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setCarModeLocked(false, 0); + // Determine if the caller has enabled car mode at a priority other than the + // default one. If they have, then attempt to disable at that priority. + int priority = mCarModePackagePriority.entrySet() + .stream() + .filter(e -> e.getValue().equals(callingPackage)) + .findFirst() + .map(Map.Entry::getKey) + .orElse(UiModeManager.DEFAULT_PRIORITY); + + setCarModeLocked(false, carModeFlags, priority, callingPackage); if (mSystemReady) { updateLocked(0, flags); } @@ -424,14 +524,30 @@ final class UiModeManagerService extends SystemService { try { synchronized (mLock) { if (mNightMode != mode) { + if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + try { + getContext().unregisterReceiver(mOnScreenOffHandler); + } catch (IllegalArgumentException e) { + // we ignore this exception if the receiver is unregistered already. + } + } // Only persist setting if not in car mode if (!mCarModeEnabled) { Secure.putIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, mode, user); + Secure.putIntForUser(getContext().getContentResolver(), + OVERRIDE_NIGHT_MODE, mNightModeOverride, user); } mNightMode = mode; - updateLocked(0, 0); + mNightModeOverride = mode; + //on screen off will update configuration instead + if (mNightMode != UiModeManager.MODE_NIGHT_AUTO) { + updateLocked(0, 0); + } else { + getContext().registerReceiver( + mOnScreenOffHandler, new IntentFilter(ACTION_SCREEN_OFF)); + } } } } finally { @@ -471,25 +587,66 @@ final class UiModeManagerService extends SystemService { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; dumpImpl(pw); } + + @Override + public boolean setNightModeActivated(boolean active) { + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + try { + getContext().unregisterReceiver(mOnScreenOffHandler); + } catch (IllegalArgumentException e) { + } + mNightModeOverride = active + ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO; + } else if (mNightMode == UiModeManager.MODE_NIGHT_NO + && active) { + mNightMode = UiModeManager.MODE_NIGHT_YES; + } else if (mNightMode == UiModeManager.MODE_NIGHT_YES + && !active) { + mNightMode = UiModeManager.MODE_NIGHT_NO; + } + updateConfigurationLocked(); + sendConfigurationLocked(); + return true; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } }; void dumpImpl(PrintWriter pw) { synchronized (mLock) { pw.println("Current UI Mode Service state:"); pw.print(" mDockState="); pw.print(mDockState); - pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" ("); - pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); - pw.print(" mNightModeLocked="); pw.print(mNightModeLocked); - pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); - pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); - pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); - pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); + pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); + pw.print(" mNightModeLocked="); pw.println(mNightModeLocked); + + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" (carModeApps="); + for (Map.Entry<Integer, String> entry : mCarModePackagePriority.entrySet()) { + pw.print(entry.getKey()); + pw.print(":"); + pw.print(entry.getValue()); + pw.print(" "); + } + pw.println(""); + pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); + pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); + pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); + pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); - pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); - pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); + pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); + pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); + pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); - pw.print(" mSystemReady="); pw.println(mSystemReady); + pw.print(" mSystemReady="); pw.println(mSystemReady); + if (mTwilightManager != null) { // We may not have a TwilightManager. pw.print(" mTwilightService.getLastTwilightState()="); @@ -512,12 +669,32 @@ final class UiModeManagerService extends SystemService { } } - void setCarModeLocked(boolean enabled, int flags) { - if (mCarModeEnabled != enabled) { - mCarModeEnabled = enabled; + /** + * Updates the global car mode state. + * The device is considered to be in car mode if there exists an app at any priority level which + * has entered car mode. + * + * @param enabled {@code true} if the caller wishes to enable car mode, {@code false} otherwise. + * @param flags Flags used when enabling/disabling car mode. + * @param priority The priority level for entering or exiting car mode; defaults to + * {@link UiModeManager#DEFAULT_PRIORITY} for callers using + * {@link UiModeManager#enableCarMode(int)}. Callers using + * {@link UiModeManager#enableCarMode(int, int)} may specify a priority. + * @param packageName The package name of the app which initiated the request to enable or + * disable car mode. + */ + void setCarModeLocked(boolean enabled, int flags, int priority, String packageName) { + if (enabled) { + enableCarMode(priority, packageName); + } else { + disableCarMode(flags, priority, packageName); + } + boolean isCarModeNowEnabled = isCarModeEnabled(); + if (mCarModeEnabled != isCarModeNowEnabled) { + mCarModeEnabled = isCarModeNowEnabled; // When exiting car mode, restore night mode from settings - if (!mCarModeEnabled) { + if (!isCarModeNowEnabled) { Context context = getContext(); updateNightModeFromSettings(context, context.getResources(), @@ -527,11 +704,102 @@ final class UiModeManagerService extends SystemService { mCarModeEnableFlags = flags; } + /** + * Handles disabling car mode. + * <p> + * Car mode can be disabled at a priority level if any of the following is true: + * 1. The priority being disabled is the {@link UiModeManager#DEFAULT_PRIORITY}. + * 2. The priority level is enabled and the caller is the app who originally enabled it. + * 3. The {@link UiModeManager#DISABLE_CAR_MODE_ALL_PRIORITIES} flag was specified, meaning all + * car mode priorities are disabled. + * + * @param flags Car mode flags. + * @param priority The priority level at which to disable car mode. + * @param packageName The calling package which initiated the request. + */ + private void disableCarMode(int flags, int priority, String packageName) { + boolean isDisableAll = (flags & UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES) != 0; + boolean isPriorityTracked = mCarModePackagePriority.keySet().contains(priority); + boolean isDefaultPriority = priority == UiModeManager.DEFAULT_PRIORITY; + boolean isChangeAllowed = + // Anyone can disable the default priority. + isDefaultPriority + // If priority was enabled, only enabling package can disable it. + || isPriorityTracked && mCarModePackagePriority.get(priority).equals(packageName) + // Disable all priorities flag can disable all regardless. + || isDisableAll; + if (isChangeAllowed) { + Slog.d(TAG, "disableCarMode: disabling, priority=" + priority + + ", packageName=" + packageName); + if (isDisableAll) { + Set<Map.Entry<Integer, String>> entries = + new ArraySet<>(mCarModePackagePriority.entrySet()); + mCarModePackagePriority.clear(); + + for (Map.Entry<Integer, String> entry : entries) { + notifyCarModeDisabled(entry.getKey(), entry.getValue()); + } + } else { + mCarModePackagePriority.remove(priority); + notifyCarModeDisabled(priority, packageName); + } + } + } + + /** + * Handles enabling car mode. + * <p> + * Car mode can be enabled at any priority if it has not already been enabled at that priority. + * The calling package is tracked for the first app which enters priority at the + * {@link UiModeManager#DEFAULT_PRIORITY}, though any app can disable it at that priority. + * + * @param priority The priority for enabling car mode. + * @param packageName The calling package which initiated the request. + */ + private void enableCarMode(int priority, String packageName) { + boolean isPriorityTracked = mCarModePackagePriority.containsKey(priority); + boolean isPackagePresent = mCarModePackagePriority.containsValue(packageName); + if (!isPriorityTracked && !isPackagePresent) { + Slog.d(TAG, "enableCarMode: enabled at priority=" + priority + ", packageName=" + + packageName); + mCarModePackagePriority.put(priority, packageName); + notifyCarModeEnabled(priority, packageName); + } else { + Slog.d(TAG, "enableCarMode: car mode at priority " + priority + " already enabled."); + } + + } + + private void notifyCarModeEnabled(int priority, String packageName) { + Intent intent = new Intent(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED); + intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName); + intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL, + android.Manifest.permission.HANDLE_CAR_MODE_CHANGES); + } + + private void notifyCarModeDisabled(int priority, String packageName) { + Intent intent = new Intent(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED); + intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName); + intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL, + android.Manifest.permission.HANDLE_CAR_MODE_CHANGES); + } + + /** + * Determines if car mode is enabled at any priority level. + * @return {@code true} if car mode is enabled, {@code false} otherwise. + */ + private boolean isCarModeEnabled() { + return mCarModePackagePriority.size() > 0; + } + private void updateDockState(int newState) { synchronized (mLock) { if (newState != mDockState) { mDockState = newState; - setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0); + setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0, + UiModeManager.DEFAULT_PRIORITY, "" /* packageName */); if (mSystemReady) { updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0); } @@ -598,6 +866,8 @@ final class UiModeManagerService extends SystemService { if (!mHoldingConfiguration) { mConfiguration.uiMode = uiMode; } + // load splash screen instead of screenshot + mWindowManager.clearSnapshotCache(); } private void sendConfigurationLocked() { @@ -848,6 +1118,20 @@ final class UiModeManagerService extends SystemService { if (state != null) { mComputedNightMode = state.isNight(); } + if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { + mComputedNightMode = true; + return; + } + if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { + mComputedNightMode = false; + return; + } + + mNightModeOverride = mNightMode; + final int user = UserHandle.getCallingUserId(); + Secure.putIntForUser(getContext().getContentResolver(), + OVERRIDE_NIGHT_MODE, mNightModeOverride, user); + } } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index b8acd7ac108a..3330882cc07d 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -28,8 +28,8 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.input.InputManager; +import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.V1_0.EffectStrength; -import android.hardware.vibrator.V1_4.Capabilities; import android.icu.text.DateFormat; import android.media.AudioAttributes; import android.media.AudioManager; @@ -1154,7 +1154,7 @@ public class VibratorService extends IVibratorService.Stub long duration = vibratorPerformEffect(prebaked.getId(), prebaked.getEffectStrength(), vib); long timeout = duration; - if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) { + if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) { timeout *= ASYNC_TIMEOUT_MULTIPLIER; } if (timeout > 0) { diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 83ad4e7e7100..454941ccdb03 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -89,6 +89,7 @@ public class Watchdog extends Thread { "/system/bin/drmserver", "/system/bin/mediadrmserver", "/system/bin/mediaserver", + "/system/bin/netd", "/system/bin/sdcard", "/system/bin/surfaceflinger", "/system/bin/vold", diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 709f3f82d4c5..ae5ad7ea1261 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -126,6 +126,12 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void clearOverridesForTest(String packageName) { + CompatConfig config = CompatConfig.get(); + config.removePackageOverrides(packageName); + } + + @Override public boolean clearOverride(long changeId, String packageName) { boolean existed = CompatConfig.get().removeOverride(changeId, packageName); killPackage(packageName); diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java index 23d0b40f08f6..11a397948b14 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java @@ -40,16 +40,16 @@ public final class RuleXmlParser implements RuleParser { public static final String TAG = "RuleXmlParser"; - // TODO: Use XML attributes + private static final String NAMESPACE = ""; private static final String RULE_LIST_TAG = "RL"; private static final String RULE_TAG = "R"; private static final String OPEN_FORMULA_TAG = "OF"; private static final String ATOMIC_FORMULA_TAG = "AF"; - private static final String EFFECT_TAG = "E"; - private static final String KEY_TAG = "K"; - private static final String OPERATOR_TAG = "O"; - private static final String VALUE_TAG = "V"; - private static final String CONNECTOR_TAG = "C"; + private static final String EFFECT_ATTRIBUTE = "E"; + private static final String KEY_ATTRIBUTE = "K"; + private static final String OPERATOR_ATTRIBUTE = "O"; + private static final String VALUE_ATTRIBUTE = "V"; + private static final String CONNECTOR_ATTRIBUTE = "C"; @Override public List<Rule> parse(String ruleText) throws RuleParseException { @@ -106,7 +106,7 @@ public final class RuleXmlParser implements RuleParser { private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException { Formula formula = null; - @Rule.Effect int effect = 0; + @Rule.Effect int effect = Integer.parseInt(extractAttributeValue(parser, EFFECT_ATTRIBUTE)); int eventType; while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -124,9 +124,6 @@ public final class RuleXmlParser implements RuleParser { case ATOMIC_FORMULA_TAG: formula = parseAtomicFormula(parser); break; - case EFFECT_TAG: - effect = Integer.parseInt(extractValue(parser)); - break; default: throw new RuntimeException( String.format("Found unexpected tag: %s", nodeName)); @@ -142,7 +139,8 @@ public final class RuleXmlParser implements RuleParser { private static Formula parseOpenFormula(XmlPullParser parser) throws IOException, XmlPullParserException { - @OpenFormula.Connector int connector = 0; + @OpenFormula.Connector int connector = Integer.parseInt( + extractAttributeValue(parser, CONNECTOR_ATTRIBUTE)); List<Formula> formulas = new ArrayList<>(); int eventType; @@ -155,9 +153,6 @@ public final class RuleXmlParser implements RuleParser { if (eventType == XmlPullParser.START_TAG) { switch (nodeName) { - case CONNECTOR_TAG: - connector = Integer.parseInt(extractValue(parser)); - break; case ATOMIC_FORMULA_TAG: formulas.add(parseAtomicFormula(parser)); break; @@ -179,37 +174,16 @@ public final class RuleXmlParser implements RuleParser { private static Formula parseAtomicFormula(XmlPullParser parser) throws IOException, XmlPullParserException { - @AtomicFormula.Key int key = 0; - @AtomicFormula.Operator int operator = 0; - String value = null; + @AtomicFormula.Key int key = Integer.parseInt(extractAttributeValue(parser, KEY_ATTRIBUTE)); + @AtomicFormula.Operator int operator = Integer.parseInt( + extractAttributeValue(parser, OPERATOR_ATTRIBUTE)); + String value = extractAttributeValue(parser, VALUE_ATTRIBUTE); int eventType; while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { - String nodeName = parser.getName(); - if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ATOMIC_FORMULA_TAG)) { break; } - - if (eventType == XmlPullParser.START_TAG) { - switch (nodeName) { - case KEY_TAG: - key = Integer.parseInt(extractValue(parser)); - break; - case OPERATOR_TAG: - operator = Integer.parseInt(extractValue(parser)); - break; - case VALUE_TAG: - value = extractValue(parser); - break; - default: - throw new RuntimeException( - String.format("Found unexpected tag: %s", nodeName)); - } - } else { - throw new RuntimeException( - String.format("Found unexpected event type: %d", eventType)); - } } return constructAtomicFormulaBasedOnKey(key, operator, value); } @@ -231,17 +205,11 @@ public final class RuleXmlParser implements RuleParser { } } - private static String extractValue(XmlPullParser parser) - throws IOException, XmlPullParserException { - String value; - int eventType = parser.next(); - if (eventType == XmlPullParser.TEXT) { - value = parser.getText(); - eventType = parser.next(); - if (eventType == XmlPullParser.END_TAG) { - return value; - } + private static String extractAttributeValue(XmlPullParser parser, String attribute) { + String attributeValue = parser.getAttributeValue(NAMESPACE, attribute); + if (attributeValue == null) { + throw new RuntimeException(String.format("Attribute not found: %s", attribute)); } - throw new RuntimeException(String.format("Found unexpected event type: %d", eventType)); + return attributeValue; } } diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java index b0805fc488cb..1f22afb0e9bf 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -43,11 +43,11 @@ public class RuleXmlSerializer implements RuleSerializer { private static final String RULE_TAG = "R"; private static final String OPEN_FORMULA_TAG = "OF"; private static final String ATOMIC_FORMULA_TAG = "AF"; - private static final String EFFECT_TAG = "E"; - private static final String KEY_TAG = "K"; - private static final String OPERATOR_TAG = "O"; - private static final String VALUE_TAG = "V"; - private static final String CONNECTOR_TAG = "C"; + private static final String EFFECT_ATTRIBUTE = "E"; + private static final String KEY_ATTRIBUTE = "K"; + private static final String OPERATOR_ATTRIBUTE = "O"; + private static final String VALUE_ATTRIBUTE = "V"; + private static final String CONNECTOR_ATTRIBUTE = "C"; @Override public void serialize(List<Rule> rules, OutputStream outputStream) @@ -88,8 +88,8 @@ public class RuleXmlSerializer implements RuleSerializer { return; } xmlSerializer.startTag(NAMESPACE, RULE_TAG); + serializeAttributeValue(EFFECT_ATTRIBUTE, String.valueOf(rule.getEffect()), xmlSerializer); serializeFormula(rule.getFormula(), xmlSerializer); - serializeValue(EFFECT_TAG, String.valueOf(rule.getEffect()), xmlSerializer); xmlSerializer.endTag(NAMESPACE, RULE_TAG); } @@ -110,7 +110,8 @@ public class RuleXmlSerializer implements RuleSerializer { return; } xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG); - serializeValue(CONNECTOR_TAG, String.valueOf(openFormula.getConnector()), xmlSerializer); + serializeAttributeValue(CONNECTOR_ATTRIBUTE, String.valueOf(openFormula.getConnector()), + xmlSerializer); for (Formula formula : openFormula.getFormulas()) { serializeFormula(formula, xmlSerializer); } @@ -123,19 +124,20 @@ public class RuleXmlSerializer implements RuleSerializer { return; } xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG); - serializeValue(KEY_TAG, String.valueOf(atomicFormula.getKey()), xmlSerializer); + serializeAttributeValue(KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), + xmlSerializer); if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) { - serializeValue(VALUE_TAG, + serializeAttributeValue(VALUE_ATTRIBUTE, ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer); } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) { - serializeValue(OPERATOR_TAG, + serializeAttributeValue(OPERATOR_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()), xmlSerializer); - serializeValue(VALUE_TAG, + serializeAttributeValue(VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()), xmlSerializer); } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) { - serializeValue(VALUE_TAG, + serializeAttributeValue(VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()), xmlSerializer); } else { @@ -145,13 +147,12 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG); } - private void serializeValue(String tag, String value, XmlSerializer xmlSerializer) + private void serializeAttributeValue(String attribute, String value, + XmlSerializer xmlSerializer) throws IOException { if (value == null) { return; } - xmlSerializer.startTag(NAMESPACE, tag); - xmlSerializer.text(value); - xmlSerializer.endTag(NAMESPACE, tag); + xmlSerializer.attribute(NAMESPACE, attribute, value); } } diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING new file mode 100644 index 000000000000..2e21fa67a967 --- /dev/null +++ b/services/core/java/com/android/server/location/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "CtsLocationCoarseTestCases" + }, + { + "name": "CtsLocationNoneTestCases" + } + ] +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java new file mode 100644 index 000000000000..91c9253269a3 --- /dev/null +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.media; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Intent; +import android.media.MediaRoute2Info; +import android.media.MediaRoute2ProviderInfo; + +import java.util.Objects; + +abstract class MediaRoute2Provider { + final ComponentName mComponentName; + final String mUniqueId; + + private Callback mCallback; + private MediaRoute2ProviderInfo mProviderInfo; + + MediaRoute2Provider(@NonNull ComponentName componentName) { + mComponentName = Objects.requireNonNull(componentName, "Component name must not be null."); + mUniqueId = componentName.flattenToShortString(); + } + + public void setCallback(MediaRoute2ProviderProxy.Callback callback) { + mCallback = callback; + } + + public abstract void requestSelectRoute(String packageName, String routeId, int seq); + public abstract void unselectRoute(String packageName, String routeId); + public abstract void sendControlRequest(MediaRoute2Info route, Intent request); + public abstract void requestSetVolume(MediaRoute2Info route, int volume); + public abstract void requestUpdateVolume(MediaRoute2Info route, int delta); + + @NonNull + public String getUniqueId() { + return mUniqueId; + } + + @Nullable + public MediaRoute2ProviderInfo getProviderInfo() { + return mProviderInfo; + } + + void setAndNotifyProviderInfo(MediaRoute2ProviderInfo info) { + //TODO: check if info is not updated + if (info == null) { + mProviderInfo = null; + } else { + mProviderInfo = new MediaRoute2ProviderInfo.Builder(info) + .setUniqueId(mUniqueId) + .build(); + } + if (mCallback != null) { + mCallback.onProviderStateChanged(this); + } + } + + public boolean hasComponentName(String packageName, String className) { + return mComponentName.getPackageName().equals(packageName) + && mComponentName.getClassName().equals(className); + } + + public interface Callback { + void onProviderStateChanged(MediaRoute2Provider provider); + } +} diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java index 51a0df33bc65..3b6580ad7357 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -17,7 +17,6 @@ package com.android.server.media; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -42,20 +41,14 @@ import java.util.Objects; /** * Maintains a connection to a particular media route provider service. */ -final class MediaRoute2ProviderProxy implements ServiceConnection { +final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements ServiceConnection { private static final String TAG = "MR2ProviderProxy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; - private final ComponentName mComponentName; - private final String mUniqueId; private final int mUserId; private final Handler mHandler; - private Callback mCallback; - - private MediaRoute2ProviderInfo mProviderInfo; - // Connection state private boolean mRunning; private boolean mBound; @@ -64,9 +57,8 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { MediaRoute2ProviderProxy(@NonNull Context context, @NonNull ComponentName componentName, int userId) { + super(componentName); mContext = Objects.requireNonNull(context, "Context must not be null."); - mComponentName = Objects.requireNonNull(componentName, "Component name must not be null."); - mUniqueId = componentName.flattenToShortString(); mUserId = userId; mHandler = new Handler(); } @@ -80,10 +72,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { pw.println(prefix + " mConnectionReady=" + mConnectionReady); } - public void setCallback(Callback callback) { - mCallback = callback; - } - + @Override public void requestSelectRoute(String packageName, String routeId, int seq) { if (mConnectionReady) { mActiveConnection.requestSelectRoute(packageName, routeId, seq); @@ -91,6 +80,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } } + @Override public void unselectRoute(String packageName, String routeId) { if (mConnectionReady) { mActiveConnection.unselectRoute(packageName, routeId); @@ -98,6 +88,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } } + @Override public void sendControlRequest(MediaRoute2Info route, Intent request) { if (mConnectionReady) { mActiveConnection.sendControlRequest(route.getId(), request); @@ -105,6 +96,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } } + @Override public void requestSetVolume(MediaRoute2Info route, int volume) { if (mConnectionReady) { mActiveConnection.requestSetVolume(route.getId(), volume); @@ -112,6 +104,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } } + @Override public void requestUpdateVolume(MediaRoute2Info route, int delta) { if (mConnectionReady) { mActiveConnection.requestUpdateVolume(route.getId(), delta); @@ -119,16 +112,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { } } - @NonNull - public String getUniqueId() { - return mUniqueId; - } - - @Nullable - public MediaRoute2ProviderInfo getProviderInfo() { - return mProviderInfo; - } - public boolean hasComponentName(String packageName, String className) { return mComponentName.getPackageName().equals(packageName) && mComponentName.getClassName().equals(className); @@ -270,20 +253,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { setAndNotifyProviderInfo(info); } - private void setAndNotifyProviderInfo(MediaRoute2ProviderInfo info) { - //TODO: check if info is not updated - if (info == null) { - mProviderInfo = null; - } else { - mProviderInfo = new MediaRoute2ProviderInfo.Builder(info) - .setUniqueId(mUniqueId) - .build(); - } - if (mCallback != null) { - mCallback.onProviderStateChanged(MediaRoute2ProviderProxy.this); - } - } - private void disconnect() { if (mActiveConnection != null) { mConnectionReady = false; @@ -298,10 +267,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection { return "Service connection " + mComponentName.flattenToShortString(); } - public interface Callback { - void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider); - } - private final class Connection implements DeathRecipient { private final IMediaRoute2Provider mProvider; private final ProviderClient mClient; diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index adfb9cb0964e..7820cd705193 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -728,14 +728,15 @@ class MediaRouter2ServiceImpl { static final class UserHandler extends Handler implements MediaRoute2ProviderWatcher.Callback, - MediaRoute2ProviderProxy.Callback { + MediaRoute2Provider.Callback { private final WeakReference<MediaRouter2ServiceImpl> mServiceRef; private final UserRecord mUserRecord; private final MediaRoute2ProviderWatcher mWatcher; //TODO: Make this thread-safe. - private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders = + private final SystemMediaRoute2Provider mSystemProvider; + private final ArrayList<MediaRoute2Provider> mMediaProviders = new ArrayList<>(); private final List<MediaRoute2ProviderInfo> mProviderInfos = new ArrayList<>(); @@ -746,6 +747,8 @@ class MediaRouter2ServiceImpl { super(Looper.getMainLooper(), null, true); mServiceRef = new WeakReference<>(service); mUserRecord = userRecord; + mSystemProvider = new SystemMediaRoute2Provider(service.mContext, this); + mMediaProviders.add(mSystemProvider); mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this, this, mUserRecord.mUserId); } @@ -777,7 +780,7 @@ class MediaRouter2ServiceImpl { } @Override - public void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider) { + public void onProviderStateChanged(@NonNull MediaRoute2Provider provider) { sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider)); } @@ -790,7 +793,7 @@ class MediaRouter2ServiceImpl { controlHints, seq)); } - private void updateProvider(MediaRoute2ProviderProxy provider) { + private void updateProvider(MediaRoute2Provider provider) { int providerIndex = getProviderInfoIndex(provider.getUniqueId()); MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo(); MediaRoute2ProviderInfo prevInfo = @@ -954,7 +957,7 @@ class MediaRouter2ServiceImpl { private void requestSelectRoute(String clientPackageName, MediaRoute2Info route, int seq) { if (route != null) { - MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); + MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider == null) { Slog.w(TAG, "Ignoring to select route of unknown provider " + route); } else { @@ -965,7 +968,7 @@ class MediaRouter2ServiceImpl { private void unselectRoute(String clientPackageName, MediaRoute2Info route) { if (route != null) { - MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); + MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider == null) { Slog.w(TAG, "Ignoring to unselect route of unknown provider " + route); } else { @@ -975,21 +978,21 @@ class MediaRouter2ServiceImpl { } private void sendControlRequest(MediaRoute2Info route, Intent request) { - final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); + final MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider != null) { provider.sendControlRequest(route, request); } } private void requestSetVolume(MediaRoute2Info route, int volume) { - final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); + final MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider != null) { provider.requestSetVolume(route, volume); } } private void requestUpdateVolume(MediaRoute2Info route, int delta) { - final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId()); + final MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider != null) { provider.requestUpdateVolume(route, delta); } @@ -1153,8 +1156,8 @@ class MediaRouter2ServiceImpl { } } - private MediaRoute2ProviderProxy findProvider(String providerId) { - for (MediaRoute2ProviderProxy provider : mMediaProviders) { + private MediaRoute2Provider findProvider(String providerId) { + for (MediaRoute2Provider provider : mMediaProviders) { if (TextUtils.equals(provider.getUniqueId(), providerId)) { return provider; } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java new file mode 100644 index 000000000000..620775e4aaba --- /dev/null +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -0,0 +1,202 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.media; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.media.AudioRoutesInfo; +import android.media.IAudioRoutesObserver; +import android.media.IAudioService; +import android.media.MediaRoute2Info; +import android.media.MediaRoute2ProviderInfo; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.R; + +/** + * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers. + */ +class SystemMediaRoute2Provider extends MediaRoute2Provider { + private static final String TAG = "MR2SystemProvider"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; + private static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE"; + + // TODO: Move these to a proper place + public static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO"; + public static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO"; + + private final AudioManager mAudioManager; + private final IAudioService mAudioService; + private final Handler mHandler; + private final Context mContext; + + private static ComponentName sComponentName = new ComponentName( + SystemMediaRoute2Provider.class.getPackageName$(), + SystemMediaRoute2Provider.class.getName()); + + //TODO: Clean up these when audio manager support multiple bt devices + MediaRoute2Info mDefaultRoute; + MediaRoute2Info mBluetoothA2dpRoute; + final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); + + final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { + @Override + public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { + mHandler.post(new Runnable() { + @Override public void run() { + updateAudioRoutes(newRoutes); + } + }); + } + }; + + SystemMediaRoute2Provider(Context context, Callback callback) { + super(sComponentName); + setCallback(callback); + + mContext = context; + mHandler = new Handler(Looper.getMainLooper()); + + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mAudioService = IAudioService.Stub.asInterface( + ServiceManager.getService(Context.AUDIO_SERVICE)); + + initializeRoutes(); + } + + //TODO: implement method + @Override + public void requestSelectRoute(@NonNull String packageName, @NonNull String routeId, int seq) { + try { + mAudioService.setBluetoothA2dpOn( + !TextUtils.equals(routeId, mDefaultRoute.getId())); + } catch (RemoteException ex) { + Log.e(TAG, "Error changing Bluetooth A2DP route"); + } + } + + //TODO: implement method + @Override + public void unselectRoute(@NonNull String packageName, @NonNull String routeId) { + // does nothing..? + } + + //TODO: implement method + @Override + public void sendControlRequest(@NonNull MediaRoute2Info route, @NonNull Intent request) { + } + + //TODO: implement method + @Override + public void requestSetVolume(MediaRoute2Info route, int volume) { + } + + //TODO: implement method + @Override + public void requestUpdateVolume(MediaRoute2Info route, int delta) { + } + + void initializeRoutes() { + //TODO: adds necessary info + mDefaultRoute = new MediaRoute2Info.Builder( + DEFAULT_ROUTE_ID, + mContext.getResources().getText(R.string.default_audio_route_name).toString()) + .setVolumeHandling(mAudioManager.isVolumeFixed() + ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED + : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) + .addSupportedCategory(CATEGORY_LIVE_AUDIO) + .addSupportedCategory(CATEGORY_LIVE_VIDEO) + .build(); + + AudioRoutesInfo newAudioRoutes = null; + try { + newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); + } catch (RemoteException e) { + } + if (newAudioRoutes != null) { + // This will select the active BT route if there is one and the current + // selected route is the default system route, or if there is no selected + // route yet. + updateAudioRoutes(newAudioRoutes); + } + + publishRoutes(); + } + + void updateAudioRoutes(AudioRoutesInfo newRoutes) { + int name = R.string.default_audio_route_name; + mCurAudioRoutesInfo.mainType = newRoutes.mainType; + if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0 + || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { + name = com.android.internal.R.string.default_audio_route_name_headphones; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { + name = com.android.internal.R.string.default_audio_route_name_dock_speakers; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { + name = com.android.internal.R.string.default_audio_route_name_hdmi; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { + name = com.android.internal.R.string.default_audio_route_name_usb; + } + + mDefaultRoute = new MediaRoute2Info.Builder( + DEFAULT_ROUTE_ID, mContext.getResources().getText(name).toString()) + .setVolumeHandling(mAudioManager.isVolumeFixed() + ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED + : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) + .addSupportedCategory(CATEGORY_LIVE_AUDIO) + .addSupportedCategory(CATEGORY_LIVE_VIDEO) + .build(); + + if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { + mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; + if (mCurAudioRoutesInfo.bluetoothName != null) { + //TODO: mark as bluetooth once MediaRoute2Info has device type + mBluetoothA2dpRoute = new MediaRoute2Info.Builder(BLUETOOTH_ROUTE_ID, + mCurAudioRoutesInfo.bluetoothName) + .setDescription(mContext.getResources().getText( + R.string.bluetooth_a2dp_audio_route_name).toString()) + .addSupportedCategory(CATEGORY_LIVE_AUDIO) + .build(); + } else { + mBluetoothA2dpRoute = null; + } + } + + publishRoutes(); + } + void publishRoutes() { + MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder() + .addRoute(mDefaultRoute); + if (mBluetoothA2dpRoute != null) { + builder.addRoute(mBluetoothA2dpRoute); + } + setAndNotifyProviderInfo(builder.build()); + } +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 3351bb1eb35b..2761987e2358 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -131,6 +131,7 @@ import android.app.role.RoleManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.companion.ICompanionDeviceManager; +import android.compat.annotation.ChangeId; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; @@ -216,6 +217,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -236,6 +238,7 @@ import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.UiThread; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import com.android.server.notification.ManagedServices.ManagedServiceInfo; @@ -355,6 +358,15 @@ public class NotificationManagerService extends SystemService { private static final int REQUEST_CODE_TIMEOUT = 1; private static final String SCHEME_TIMEOUT = "timeout"; private static final String EXTRA_KEY = "key"; + + /** + * Apps targeting R+ that post custom toasts in the background will have those blocked. Apps can + * still post toasts created with {@link Toast#makeText(Context, CharSequence, int)} and its + * variants while in the background. + */ + @ChangeId + private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L; + private IActivityManager mAm; private ActivityManager mActivityManager; private IPackageManager mPackageManager; @@ -372,9 +384,11 @@ public class NotificationManagerService extends SystemService { private UriGrantsManagerInternal mUgmInternal; private RoleObserver mRoleObserver; private UserManager mUm; + private IPlatformCompat mPlatformCompat; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; + private Handler mUiHandler; private final HandlerThread mRankingThread = new HandlerThread("ranker", Process.THREAD_PRIORITY_BACKGROUND); @@ -1782,8 +1796,11 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); mDpm = dpm; mUm = userManager; + mPlatformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mHandler = new WorkerHandler(looper); + mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); @@ -2450,9 +2467,19 @@ public class NotificationManagerService extends SystemService { // ============================================================================ @Override + public void enqueueTextToast(String pkg, ITransientNotification callback, int duration, + int displayId) { + enqueueToast(pkg, callback, duration, displayId, false); + } + + @Override public void enqueueToast(String pkg, ITransientNotification callback, int duration, - int displayId) - { + int displayId) { + enqueueToast(pkg, callback, duration, displayId, true); + } + + private void enqueueToast(String pkg, ITransientNotification callback, int duration, + int displayId, boolean isCustomToast) { if (DBG) { Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration + " displayId=" + displayId); @@ -2464,27 +2491,54 @@ public class NotificationManagerService extends SystemService { } final int callingUid = Binder.getCallingUid(); + final UserHandle callingUser = Binder.getCallingUserHandle(); final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); final boolean isPackageSuspended = isPackagePaused(pkg); final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, callingUid); + final boolean appIsForeground; long callingIdentity = Binder.clearCallingIdentity(); try { - final boolean appIsForeground = mActivityManager.getUidImportance(callingUid) + appIsForeground = mActivityManager.getUidImportance(callingUid) == IMPORTANCE_FOREGROUND; - if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage - && !appIsForeground) || isPackageSuspended)) { - Slog.e(TAG, "Suppressing toast from package " + pkg - + (isPackageSuspended ? " due to package suspended." - : " by user request.")); - return; - } } finally { Binder.restoreCallingIdentity(callingIdentity); } + if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage + && !appIsForeground) || isPackageSuspended)) { + Slog.e(TAG, "Suppressing toast from package " + pkg + + (isPackageSuspended ? " due to package suspended." + : " by user request.")); + return; + } + + if (isCustomToast && !appIsForeground && !isSystemToast) { + boolean block; + try { + block = mPlatformCompat.isChangeEnabledByPackageName( + CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, pkg, + callingUser.getIdentifier()); + } catch (RemoteException e) { + // Shouldn't happen have since it's a local local + Slog.e(TAG, "Unexpected exception while checking block background custom toasts" + + " change", e); + block = false; + } + if (block) { + // TODO(b/144152069): Remove informative toast + mUiHandler.post(() -> Toast.makeText(getContext(), + "Background custom toast blocked for package " + pkg + ".\n" + + "See go/r-toast-block.", + Toast.LENGTH_SHORT).show()); + Slog.w(TAG, "Blocking custom toast from package " + pkg + + " due to package not in the foreground"); + return; + } + } + synchronized (mToastQueue) { int callingPid = Binder.getCallingPid(); long callingId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index b3b0029326d5..26cd42daa9f8 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -354,28 +354,6 @@ public class Installer extends SystemService { } } - public void idmap(String targetApkPath, String overlayApkPath, int uid) - throws InstallerException { - if (!checkBeforeRemote()) return; - BlockGuard.getVmPolicy().onPathAccess(targetApkPath); - BlockGuard.getVmPolicy().onPathAccess(overlayApkPath); - try { - mInstalld.idmap(targetApkPath, overlayApkPath, uid); - } catch (Exception e) { - throw InstallerException.from(e); - } - } - - public void removeIdmap(String overlayApkPath) throws InstallerException { - if (!checkBeforeRemote()) return; - BlockGuard.getVmPolicy().onPathAccess(overlayApkPath); - try { - mInstalld.removeIdmap(overlayApkPath); - } catch (Exception e) { - throw InstallerException.from(e); - } - } - public void rmdex(String codePath, String instructionSet) throws InstallerException { assertValidInstructionSet(instructionSet); if (!checkBeforeRemote()) return; diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 532ff86e9014..00b525742332 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -113,18 +113,17 @@ public class StagingManager { * Validates the signature used to sign the container of the new apex package * * @param newApexPkg The new apex package that is being installed - * @param installFlags flags related to the session * @throws PackageManagerException */ - private void validateApexSignature(PackageInfo newApexPkg, int installFlags) + private void validateApexSignature(PackageInfo newApexPkg) throws PackageManagerException { // Get signing details of the new package final String apexPath = newApexPkg.applicationInfo.sourceDir; final String packageName = newApexPkg.packageName; - final SigningDetails signingDetails; + final SigningDetails newSigningDetails; try { - signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); + newSigningDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "Failed to parse APEX package " + apexPath, e); @@ -149,16 +148,10 @@ public class StagingManager { } // Verify signing details for upgrade - if (signingDetails.checkCapability(existingSigningDetails, - PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) { - return; - } - - // Verify signing details for downgrade - // Allow downgrading from B to A iff it is possible to upgrade from A to B - if (existingApexPkg.getLongVersionCode() > newApexPkg.getLongVersionCode() - && existingSigningDetails.checkCapability(signingDetails, - PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) { + if (newSigningDetails.checkCapability(existingSigningDetails, + SigningDetails.CertCapabilities.INSTALLED_DATA) + || existingSigningDetails.checkCapability(newSigningDetails, + SigningDetails.CertCapabilities.ROLLBACK)) { return; } @@ -896,8 +889,7 @@ public class StagingManager { final List<PackageInfo> apexPackages = submitSessionToApexService(session); for (PackageInfo apexPackage : apexPackages) { - validateApexSignature( - apexPackage, session.params.installFlags); + validateApexSignature(apexPackage); } } catch (PackageManagerException e) { session.setStagedSessionFailed(e.error, e.getMessage()); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8039724edf64..fcdb3b065ae6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -185,7 +185,6 @@ import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING; import static com.android.server.wm.AppWindowTokenProto.NAME; import static com.android.server.wm.AppWindowTokenProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.AppWindowTokenProto.NUM_INTERESTING_WINDOWS; -import static com.android.server.wm.AppWindowTokenProto.REMOVED; import static com.android.server.wm.AppWindowTokenProto.REPORTED_DRAWN; import static com.android.server.wm.AppWindowTokenProto.REPORTED_VISIBLE; import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED; @@ -631,9 +630,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Last visibility state we reported to the app token. boolean reportedVisible; - // Set to true when the token has been removed from the window mgr. - boolean removed; - boolean mDisablePreviewScreenshots; // Information about an application starting window if displayed. @@ -878,9 +874,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn); pw.println(")"); } - if (mStartingData != null || removed || firstWindowDrawn || mIsExiting) { + if (mStartingData != null || firstWindowDrawn || mIsExiting) { pw.print(prefix); pw.print("startingData="); pw.print(mStartingData); - pw.print(" removed="); pw.print(removed); pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); pw.print(" mIsExiting="); pw.println(mIsExiting); } @@ -1750,12 +1745,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (surface != null) { boolean abort = false; synchronized (mWmService.mGlobalLock) { - // If the window was successfully added, then - // we need to remove it. - if (removed || mStartingData == null) { - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, - "Aborted starting %s: removed=%b startingData=%s", - ActivityRecord.this, removed, mStartingData); + // If the window was successfully added, then we need to remove it. + if (mStartingData == null) { + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Aborted starting %s: startingData=%s", + ActivityRecord.this, mStartingData); startingWindow = null; mStartingData = null; @@ -1798,7 +1791,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // task snapshot starting window. return STARTING_WINDOW_TYPE_SPLASH_SCREEN; } - return snapshot == null ? STARTING_WINDOW_TYPE_NONE + return snapshot == null ? STARTING_WINDOW_TYPE_SPLASH_SCREEN : snapshotOrientationSameAsTask(snapshot) || fromRecents ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN; } else { @@ -2010,12 +2003,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A setMainWindowOpaque(occludesParent); mWmService.mWindowPlacerLocked.requestTraversal(); - if (changed && task != null) { - if (!occludesParent) { - getActivityStack().convertActivityToTranslucent(this); - } - // Keep track of the number of fullscreen activities in this task. - task.numFullscreen += occludesParent ? +1 : -1; + if (changed && task != null && !occludesParent) { + getActivityStack().convertActivityToTranslucent(this); } // Always ensure visibility if this activity doesn't occlude parent, so the // {@link #returningOptions} of the activity under this one can be applied in @@ -3040,7 +3029,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A removeIfPossible(); } - removed = true; stopFreezingScreen(true, true); final DisplayContent dc = getDisplayContent(); @@ -4134,11 +4122,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A scheduleAnimation(); } - @Override - void onAppTransitionDone() { - sendingToBottom = false; - } - /** * See {@link Activity#setDisablePreviewScreenshots}. */ @@ -6090,10 +6073,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mOrientation; } - // The {@link ActivityRecord} should only specify an orientation when it is not closing or - // going to the bottom. Allowing closing {@link ActivityRecord} to participate can lead to - // an Activity in another task being started in the wrong orientation during the transition. - if (!(sendingToBottom || getDisplayContent().mClosingApps.contains(this)) + // The {@link ActivityRecord} should only specify an orientation when it is not closing. + // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another + // task being started in the wrong orientation during the transition. + if (!getDisplayContent().mClosingApps.contains(this) && (isVisible() || getDisplayContent().mOpeningApps.contains(this))) { return mOrientation; } @@ -7348,7 +7331,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows); proto.write(ALL_DRAWN, allDrawn); proto.write(LAST_ALL_DRAWN, mLastAllDrawn); - proto.write(REMOVED, removed); if (startingWindow != null) { startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 8385232b72d8..d7e6852cb78f 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2896,7 +2896,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg Task task = null; if (!newTask) { // If starting in an existing task, find where that is... - boolean startIt = true; + boolean isOccluded = false; for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) { task = getChildAt(taskNdx); if (task.getTopNonFinishingActivity() == null) { @@ -2904,10 +2904,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg continue; } if (task == rTask) { - // Here it is! Now, if this is not yet visible to the - // user, then just add it without starting; it will - // get started when the user navigates back to it. - if (!startIt) { + // Here it is! Now, if this is not yet visible (occluded by another task) to + // the user, then just add it without starting; it will get started when the + // user navigates back to it. + if (isOccluded) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); rTask.positionChildAtTop(r); @@ -2915,8 +2915,8 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg return; } break; - } else if (task.numFullscreen > 0) { - startIt = false; + } else if (!isOccluded) { + isOccluded = task.forAllActivities(ActivityRecord::occludesParent); } } } @@ -4670,9 +4670,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg } positionChildAt(position, task, includingParents); task.updateTaskMovement(toTop); - if (getDisplayContent().mAppTransition.isTransitionSet()) { - task.setSendingToBottom(!toTop); - } getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); @@ -5214,9 +5211,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg child.updateTaskMovement(true); final DisplayContent displayContent = getDisplayContent(); - if (displayContent.mAppTransition.isTransitionSet()) { - child.setSendingToBottom(false); - } displayContent.layoutAndAssignWindowLayersIfNeeded(); } @@ -5238,10 +5232,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg } positionChildAt(POSITION_BOTTOM, child, includingParents); - - if (getDisplayContent().mAppTransition.isTransitionSet()) { - child.setSendingToBottom(true); - } getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } @@ -5284,9 +5274,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg task.updateTaskMovement(isTop); if (isTop) { final DisplayContent displayContent = getDisplayContent(); - if (displayContent.mAppTransition.isTransitionSet()) { - task.setSendingToBottom(false); - } displayContent.layoutAndAssignWindowLayersIfNeeded(); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b4dd55de2dba..db41968a6c74 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 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; @@ -601,13 +600,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ActivityRecord activity = w.mActivityRecord; - // If this window's application has been removed, just skip it. - if (activity!= null && (activity.removed || activity.sendingToBottom)) { - ProtoLog.v(WM_DEBUG_FOCUS, "Skipping %s because %s", activity, - (activity.removed ? "removed" : "sendingToBottom")); - return false; - } - if (focusedApp == null) { ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: focusedApp=null using new focus @ %s", w); @@ -865,7 +857,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWallpaperController = new WallpaperController(mWmService, this); display.getDisplayInfo(mDisplayInfo); display.getMetrics(mDisplayMetrics); - mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp + mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp * mDisplayMetrics.densityDpi / DENSITY_DEFAULT; isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY; mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo, @@ -2045,7 +2037,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void updateSystemGestureExclusionLimit() { - mSystemGestureExclusionLimit = mWmService.mSystemGestureExclusionLimitDp + mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp * mDisplayMetrics.densityDpi / DENSITY_DEFAULT; updateSystemGestureExclusion(); } @@ -4275,12 +4267,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override int getOrientation() { - if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) - || isStackVisible(WINDOWING_MODE_FREEFORM)) { + if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { // Apps and their containers are not allowed to specify an orientation while the - // docked or freeform stack is visible...except for the home stack if the docked - // stack is minimized and it actually set something and the bounds is different from - // the display. + // docked stack is visible...except for the home stack if the docked stack is + // minimized and it actually set something and the bounds is different from the + // display. if (mHomeStack != null && mHomeStack.isVisible() && mDividerControllerLocked.isMinimizedDock() && !(mDividerControllerLocked.isHomeStackResizable() @@ -5103,7 +5094,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @return Whether gesture exclusion area should be logged for the given window */ static boolean logsGestureExclusionRestrictions(WindowState win) { - if (win.mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) { + if (win.mWmService.mConstants.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) { return false; } final WindowManager.LayoutParams attrs = win.getAttrs(); diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java index 8ae740d3101b..29b6bc479f72 100644 --- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java +++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java @@ -27,9 +27,9 @@ import android.util.ArraySet; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; +import com.android.server.wm.utils.DeviceConfigInterface; import java.io.PrintWriter; -import java.util.concurrent.Executor; /** * A Blacklist for packages that should force the display out of high refresh rate. @@ -41,26 +41,20 @@ class HighRefreshRateBlacklist { private final String[] mDefaultBlacklist; private final Object mLock = new Object(); + private DeviceConfigInterface mDeviceConfig; + private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener(); + static HighRefreshRateBlacklist create(@NonNull Resources r) { - return new HighRefreshRateBlacklist(r, new DeviceConfigInterface() { - @Override - public @Nullable String getProperty(@NonNull String namespace, @NonNull String name) { - return DeviceConfig.getProperty(namespace, name); - } - public void addOnPropertiesChangedListener(@NonNull String namespace, - @NonNull Executor executor, - @NonNull DeviceConfig.OnPropertiesChangedListener listener) { - DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener); - } - }); + return new HighRefreshRateBlacklist(r, DeviceConfigInterface.REAL); } @VisibleForTesting HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) { mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist); - deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - BackgroundThread.getExecutor(), new OnPropertiesChangedListener()); - final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + mDeviceConfig = deviceConfig; + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + BackgroundThread.getExecutor(), mListener); + final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_HIGH_REFRESH_RATE_BLACKLIST); updateBlacklist(property); } @@ -101,10 +95,12 @@ class HighRefreshRateBlacklist { } } - interface DeviceConfigInterface { - @Nullable String getProperty(@NonNull String namespace, @NonNull String name); - void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor, - @NonNull DeviceConfig.OnPropertiesChangedListener listener); + /** Used to prevent WmTests leaking issues. */ + @VisibleForTesting + void dispose() { + mDeviceConfig.removeOnPropertiesChangedListener(mListener); + mDeviceConfig = null; + mBlacklistedPackages.clear(); } private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 96bac88f0984..ba3b8b7d6787 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -252,8 +252,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity // was changed. - int numFullscreen; // Number of fullscreen activities. - /** Can't be put in lockTask mode. */ final static int LOCK_TASK_AUTH_DONT_LOCK = 0; /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ @@ -1210,9 +1208,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); r.inHistory = true; - if (r.occludesParent()) { - numFullscreen++; - } // Only set this based on the first activity if (!hadChild) { if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { @@ -1256,9 +1251,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } super.removeChild(r); - if (r.occludesParent()) { - numFullscreen--; - } if (r.isPersistable()) { mAtmService.notifyTaskPersisterLocked(this, false); } @@ -2255,7 +2247,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta // We want to place all non-overlay activities below overlays. while (maxPosition > 0) { final ActivityRecord current = mChildren.get(maxPosition - 1); - if (current.mTaskOverlay && !current.removed) { + if (current.mTaskOverlay) { --maxPosition; continue; } @@ -2266,17 +2258,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } } - if (suggestedPosition >= maxPosition) { - return Math.min(maxPosition, suggestedPosition); - } - - for (int pos = 0; pos < maxPosition && pos < suggestedPosition; ++pos) { - // TODO: Confirm that this is the behavior we want long term. - if (mChildren.get(pos).removed) { - // suggestedPosition assumes removed tokens are actually gone. - ++suggestedPosition; - } - } return Math.min(maxPosition, suggestedPosition); } @@ -2339,12 +2320,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta mPreserveNonFloatingState = stack.inPinnedWindowingMode(); } - void setSendingToBottom(boolean toBottom) { - for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) { - mChildren.get(appTokenNdx).sendingToBottom = toBottom; - } - } - public int setBounds(Rect bounds, boolean forceResize) { final int boundsChanged = setBounds(bounds); @@ -2981,10 +2956,9 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta pw.print(prefix); pw.print("mActivityComponent="); pw.println(realActivity.flattenToShortString()); } - if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) { + if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) { pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); pw.print(" isPersistable="); pw.print(isPersistable); - pw.print(" numFullscreen="); pw.print(numFullscreen); pw.print(" activityType="); pw.println(getActivityType()); } if (rootWasReset || mNeverRelinquishIdentity || mReuseTask diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java index 9e55113c7705..d07516a6c86d 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -19,11 +19,8 @@ package com.android.server.wm; import android.annotation.Nullable; import android.app.ActivityManager.TaskSnapshot; import android.util.ArrayMap; -import android.util.LruCache; import java.io.PrintWriter; -import java.util.Map; -import java.util.Map.Entry; /** * Caches snapshots. See {@link TaskSnapshotController}. @@ -42,6 +39,10 @@ class TaskSnapshotCache { mLoader = loader; } + void clearRunningCache() { + mRunningCache.clear(); + } + void putSnapshot(Task task, TaskSnapshot snapshot) { final CacheEntry entry = mRunningCache.get(task.mTaskId); if (entry != null) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 35f61a88522b..f83ceb0bfc4e 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -214,6 +214,13 @@ class TaskSnapshotController { } /** + * @see WindowManagerInternal#clearSnapshotCache + */ + public void clearSnapshotCache() { + mCache.clearRunningCache(); + } + + /** * Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW * MANAGER LOCK WHEN CALLING THIS METHOD! */ diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java new file mode 100644 index 000000000000..10c8ef0eaee8 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE; +import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP; + +import android.provider.AndroidDeviceConfig; +import android.provider.DeviceConfig; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.wm.utils.DeviceConfigInterface; + +import java.io.PrintWriter; +import java.util.concurrent.Executor; + +/** + * Settings constants that can modify the window manager's behavior. + */ +final class WindowManagerConstants { + + /** + * The minimum duration between gesture exclusion logging for a given window in + * milliseconds. + * + * Events that happen in-between will be silently dropped. + * + * A non-positive value disables logging. + * + * <p>Note: On Devices running Q, this key is in the "android:window_manager" namespace. + * + * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER + */ + static final String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS = + "system_gesture_exclusion_log_debounce_millis"; + + private static final int MIN_GESTURE_EXCLUSION_LIMIT_DP = 200; + + /** @see #KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS */ + long mSystemGestureExclusionLogDebounceTimeoutMillis; + /** @see AndroidDeviceConfig#KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP */ + int mSystemGestureExclusionLimitDp; + /** @see AndroidDeviceConfig#KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE */ + boolean mSystemGestureExcludedByPreQStickyImmersive; + + private final WindowManagerGlobalLock mGlobalLock; + private final Runnable mUpdateSystemGestureExclusionCallback; + private final DeviceConfigInterface mDeviceConfig; + private final DeviceConfig.OnPropertiesChangedListener mListenerAndroid; + private final DeviceConfig.OnPropertiesChangedListener mListenerWindowManager; + + WindowManagerConstants(WindowManagerService service, DeviceConfigInterface deviceConfig) { + this(service.mGlobalLock, () -> service.mRoot.forAllDisplays( + DisplayContent::updateSystemGestureExclusionLimit), deviceConfig); + } + + @VisibleForTesting + WindowManagerConstants(WindowManagerGlobalLock globalLock, + Runnable updateSystemGestureExclusionCallback, + DeviceConfigInterface deviceConfig) { + mGlobalLock = globalLock; + mUpdateSystemGestureExclusionCallback = updateSystemGestureExclusionCallback; + mDeviceConfig = deviceConfig; + mListenerAndroid = this::onAndroidPropertiesChanged; + mListenerWindowManager = this::onWindowPropertiesChanged; + } + + void start(Executor executor) { + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ANDROID, executor, + mListenerAndroid); + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + executor, mListenerWindowManager); + + updateSystemGestureExclusionLogDebounceMillis(); + updateSystemGestureExclusionLimitDp(); + updateSystemGestureExcludedByPreQStickyImmersive(); + } + + @VisibleForTesting + void dispose() { + mDeviceConfig.removeOnPropertiesChangedListener(mListenerAndroid); + mDeviceConfig.removeOnPropertiesChangedListener(mListenerWindowManager); + } + + private void onAndroidPropertiesChanged(DeviceConfig.Properties properties) { + synchronized (mGlobalLock) { + boolean updateSystemGestureExclusionLimit = false; + for (String name : properties.getKeyset()) { + if (name == null) { + return; + } + switch (name) { + case KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP: + updateSystemGestureExclusionLimitDp(); + updateSystemGestureExclusionLimit = true; + break; + case KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE: + updateSystemGestureExcludedByPreQStickyImmersive(); + updateSystemGestureExclusionLimit = true; + break; + default: + break; + } + } + if (updateSystemGestureExclusionLimit) { + mUpdateSystemGestureExclusionCallback.run(); + } + } + } + + private void onWindowPropertiesChanged(DeviceConfig.Properties properties) { + synchronized (mGlobalLock) { + for (String name : properties.getKeyset()) { + if (name == null) { + return; + } + switch (name) { + case KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS: + updateSystemGestureExclusionLogDebounceMillis(); + break; + default: + break; + } + } + } + } + + private void updateSystemGestureExclusionLogDebounceMillis() { + mSystemGestureExclusionLogDebounceTimeoutMillis = + mDeviceConfig.getLong(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); + } + + private void updateSystemGestureExclusionLimitDp() { + mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, + mDeviceConfig.getInt(DeviceConfig.NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); + } + + private void updateSystemGestureExcludedByPreQStickyImmersive() { + mSystemGestureExcludedByPreQStickyImmersive = mDeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); + } + + void dump(PrintWriter pw) { + pw.println("WINDOW MANAGER CONSTANTS (dumpsys window constants):"); + + pw.print(" "); pw.print(KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS); + pw.print("="); pw.println(mSystemGestureExclusionLogDebounceTimeoutMillis); + pw.print(" "); pw.print(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP); + pw.print("="); pw.println(mSystemGestureExclusionLimitDp); + pw.print(" "); pw.print(KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE); + pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive); + pw.println(); + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index d2249724ae6e..46faf3b40f85 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -544,4 +544,10 @@ public abstract class WindowManagerInternal { */ public abstract @Nullable KeyInterceptionInfo getKeyInterceptionInfoFromToken(IBinder inputToken); + + /** + * Clears the snapshot cache of running activities so they show the splash-screen + * the next time the activities are opened. + */ + public abstract void clearSnapshotCache(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 519cc2165cca..2d6d5f45e5fc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -36,9 +36,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; -import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE; -import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP; -import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; @@ -188,7 +185,6 @@ import android.os.SystemService; import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; -import android.provider.DeviceConfig; import android.provider.Settings; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; @@ -280,6 +276,7 @@ import com.android.server.power.ShutdownThread; import com.android.server.protolog.ProtoLogImpl; import com.android.server.protolog.common.ProtoLog; import com.android.server.utils.PriorityDump; +import com.android.server.wm.utils.DeviceConfigInterface; import java.io.BufferedWriter; import java.io.DataInputStream; @@ -411,7 +408,8 @@ public class WindowManagerService extends IWindowManager.Stub private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000; - private static final int MIN_GESTURE_EXCLUSION_LIMIT_DP = 200; + final WindowManagerConstants mConstants = new WindowManagerConstants(this, + DeviceConfigInterface.REAL); final WindowTracing mWindowTracing; @@ -938,19 +936,6 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>(); boolean mWindowsChanged = false; - int mSystemGestureExclusionLimitDp; - boolean mSystemGestureExcludedByPreQStickyImmersive; - - /** - * The minimum duration between gesture exclusion logging for a given window in - * milliseconds. - * - * Events that happen in-between will be silently dropped. - * - * A non-positive value disables logging. - */ - public long mSystemGestureExclusionLogDebounceTimeoutMillis; - public interface WindowChangeListener { public void windowsChanged(); public void focusChanged(); @@ -1054,9 +1039,6 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<AppFreezeListener> mAppFreezeListeners = new ArrayList<>(); - @VisibleForTesting - final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener; - interface AppFreezeListener { void onAppFreezeTimeout(); } @@ -1261,38 +1243,7 @@ public class WindowManagerService extends IWindowManager.Stub mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources()); - mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, - DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); - mSystemGestureExclusionLogDebounceTimeoutMillis = - DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); - mSystemGestureExcludedByPreQStickyImmersive = - DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); - - mPropertiesChangedListener = properties -> { - synchronized (mGlobalLock) { - final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, - DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); - final boolean excludedByPreQSticky = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); - if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky - || mSystemGestureExclusionLimitDp != exclusionLimitDp) { - mSystemGestureExclusionLimitDp = exclusionLimitDp; - mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky; - mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit); - } - - mSystemGestureExclusionLogDebounceTimeoutMillis = - DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); - } - }; - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - new HandlerExecutor(mH), mPropertiesChangedListener); + mConstants.start(new HandlerExecutor(mH)); LocalServices.addService(WindowManagerInternal.class, new LocalService()); mEmbeddedWindowController = new EmbeddedWindowController(mGlobalLock); @@ -1473,7 +1424,7 @@ public class WindowManagerService extends IWindowManager.Stub ProtoLog.w(WM_ERROR, "Attempted to add window with non-application token " + ".%s Aborting.", token); return WindowManagerGlobal.ADD_NOT_APP_TOKEN; - } else if (activity.removed) { + } else if (activity.getParent() == null) { ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token " + ".%s Aborting.", token); return WindowManagerGlobal.ADD_APP_EXITING; @@ -6199,6 +6150,9 @@ public class WindowManagerService extends IWindowManager.Stub } else if ("refresh".equals(cmd)) { dumpHighRefreshRateBlacklist(pw); return; + } else if ("constants".equals(cmd)) { + mConstants.dump(pw); + return; } else { // Dumping a single name? if (!dumpWindows(pw, cmd, args, opti, dumpAll)) { @@ -6262,6 +6216,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(separator); } dumpHighRefreshRateBlacklist(pw); + if (dumpAll) { + pw.println(separator); + } + mConstants.dump(pw); } } @@ -6945,6 +6903,14 @@ public class WindowManagerService extends IWindowManager.Stub } private final class LocalService extends WindowManagerInternal { + + @Override + public void clearSnapshotCache() { + synchronized (mGlobalLock) { + mTaskSnapshotController.clearSnapshotCache(); + } + } + @Override public void requestTraversalFromDisplayManager() { synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index db0f3bc139bc..d41e70692eba 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -701,7 +701,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY; final boolean immersiveSticky = (mSystemUiVisibility & immersiveStickyFlags) == immersiveStickyFlags; - return immersiveSticky && mWmService.mSystemGestureExcludedByPreQStickyImmersive + return immersiveSticky && mWmService.mConstants.mSystemGestureExcludedByPreQStickyImmersive && mActivityRecord != null && mActivityRecord.mTargetSdk < Build.VERSION_CODES.Q; } @@ -3040,7 +3040,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private void logExclusionRestrictions(int side) { if (!logsGestureExclusionRestrictions(this) || SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side] - + mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis) { + + mWmService.mConstants.mSystemGestureExclusionLogDebounceTimeoutMillis) { // Drop the log if we have just logged; this is okay, because what we would have logged // was true only for a short duration. return; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 88a1458a783f..057f4931dec1 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -82,10 +82,6 @@ class WindowToken extends WindowContainer<WindowState> { // will be shown. boolean waitingToShow; - // Set to true when this token is in a pending transaction where its - // windows will be put to the bottom of the list. - boolean sendingToBottom; - /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */ final boolean mOwnerCanManageAppTokens; @@ -298,9 +294,8 @@ class WindowToken extends WindowContainer<WindowState> { pw.print(prefix); pw.print("windowType="); pw.print(windowType); pw.print(" hidden="); pw.print(mHidden); pw.print(" hasVisible="); pw.println(hasVisible); - if (waitingToShow || sendingToBottom) { + if (waitingToShow) { pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); - pw.print(" sendingToBottom="); pw.print(sendingToBottom); } } diff --git a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java b/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java new file mode 100644 index 000000000000..ab7e7f63cafd --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.utils; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.provider.DeviceConfig; + +import java.util.concurrent.Executor; + +/** + * Abstraction around {@link DeviceConfig} to allow faking device configuration in tests. + */ +public interface DeviceConfigInterface { + /** + * @see DeviceConfig#getProperty + */ + @Nullable + String getProperty(@NonNull String namespace, @NonNull String name); + + /** + * @see DeviceConfig#getString + */ + @NonNull + String getString(@NonNull String namespace, @NonNull String name, @NonNull String defaultValue); + + /** + * @see DeviceConfig#getInt + */ + int getInt(@NonNull String namespace, @NonNull String name, int defaultValue); + + /** + * @see DeviceConfig#getLong + */ + long getLong(@NonNull String namespace, @NonNull String name, long defaultValue); + + /** + * @see DeviceConfig#getBoolean + */ + boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue); + + /** + * @see DeviceConfig#addOnPropertiesChangedListener + */ + void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor, + @NonNull DeviceConfig.OnPropertiesChangedListener listener); + + /** + * @see DeviceConfig#removeOnPropertiesChangedListener + */ + void removeOnPropertiesChangedListener( + @NonNull DeviceConfig.OnPropertiesChangedListener listener); + + /** + * Calls through to the real {@link DeviceConfig}. + */ + DeviceConfigInterface REAL = new DeviceConfigInterface() { + @Override + public String getProperty(String namespace, String name) { + return DeviceConfig.getProperty(namespace, name); + } + + @Override + public String getString(String namespace, String name, String defaultValue) { + return DeviceConfig.getString(namespace, name, defaultValue); + } + + @Override + public int getInt(String namespace, String name, int defaultValue) { + return DeviceConfig.getInt(namespace, name, defaultValue); + } + + @Override + public long getLong(String namespace, String name, long defaultValue) { + return DeviceConfig.getLong(namespace, name, defaultValue); + } + + @Override + public boolean getBoolean(@NonNull String namespace, @NonNull String name, + boolean defaultValue) { + return DeviceConfig.getBoolean(namespace, name, defaultValue); + } + + @Override + public void addOnPropertiesChangedListener(String namespace, Executor executor, + DeviceConfig.OnPropertiesChangedListener listener) { + DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener); + } + + @Override + public void removeOnPropertiesChangedListener( + DeviceConfig.OnPropertiesChangedListener listener) { + DeviceConfig.removeOnPropertiesChangedListener(listener); + } + }; +} diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 425b4b632971..dd2b27ddeef4 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -141,7 +141,6 @@ cc_defaults { "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", - "android.hardware.vibrator@1.4", "android.hardware.vr@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 372622801aa0..746610df11ae 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "VibratorService" -#include <android/hardware/vibrator/1.4/IVibrator.h> +#include <android/hardware/vibrator/1.3/IVibrator.h> #include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> #include <binder/IServiceManager.h> @@ -43,166 +43,41 @@ namespace V1_0 = android::hardware::vibrator::V1_0; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_3 = android::hardware::vibrator::V1_3; -namespace V1_4 = android::hardware::vibrator::V1_4; namespace aidl = android::hardware::vibrator; namespace android { static jmethodID sMethodIdOnComplete; -// TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove -// shim -class VibratorShim : public V1_4::IVibrator { - public: - VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {} - - Return<V1_0::Status> on(uint32_t timeoutMs) override { - return on_1_4(timeoutMs, nullptr); - } - - Return<V1_0::Status> off() override { - return toHidlStatus(mVib->off()); - } - - Return<bool> supportsAmplitudeControl() override { - int32_t cap = 0; - if (!mVib->getCapabilities(&cap).isOk()) return false; - if (mUnderExternalControl) { - return (cap & aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0; - } else { - return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; - } - } - - Return<V1_0::Status> setAmplitude(uint8_t amplitude) override { - return toHidlStatus(mVib->setAmplitude(amplitude)); - } - - Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength, - perform_cb _hidl_cb) override { - return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); - } - - Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, - perform_1_1_cb _hidl_cb) override { - return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); - } - - Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength, - perform_1_2_cb _hidl_cb) override { - return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); - } - - Return<bool> supportsExternalControl() override { - int32_t cap = 0; - if (!mVib->getCapabilities(&cap).isOk()) return false; - return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; - } - - Return<V1_0::Status> setExternalControl(bool enabled) override { - Return<V1_0::Status> status = toHidlStatus(mVib->setExternalControl(enabled)); - if (status.isOk() && status == V1_0::Status::OK) { - mUnderExternalControl = enabled; - } - return status; - } - - Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength, - perform_1_3_cb _hidl_cb) override { - return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); - } - - Return<uint32_t> getCapabilities() override { - static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) == - static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK)); - static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) == - static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK)); - - int32_t cap; - if (!mVib->getCapabilities(&cap).isOk()) return 0; - return (cap & (aidl::IVibrator::CAP_ON_CALLBACK | - aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0; - } - - Return<V1_0::Status> on_1_4(uint32_t timeoutMs, - const sp<V1_4::IVibratorCallback>& callback) override { - sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; - return toHidlStatus(mVib->on(timeoutMs, cb)); - } - - Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength, - const sp<V1_4::IVibratorCallback>& callback, - perform_1_4_cb _hidl_cb) override { - static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == - static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); - static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == - static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); - static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == - static_cast<uint8_t>(aidl::EffectStrength::STRONG)); - static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == - static_cast<uint8_t>(aidl::Effect::CLICK)); - static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == - static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK)); - static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == - static_cast<uint8_t>(aidl::Effect::TICK)); - static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == - static_cast<uint8_t>(aidl::Effect::THUD)); - static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == - static_cast<uint8_t>(aidl::Effect::POP)); - static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) == - static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK)); - static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) == - static_cast<uint8_t>(aidl::Effect::RINGTONE_1)); - static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) == - static_cast<uint8_t>(aidl::Effect::RINGTONE_2)); - static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == - static_cast<uint8_t>(aidl::Effect::RINGTONE_15)); - static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == - static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); - - sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; - int timeoutMs = 0; - Return<V1_0::Status> status = toHidlStatus( - mVib->perform(static_cast<aidl::Effect>(effect), - static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs)); - - if (status.isOk()) { - _hidl_cb(status, timeoutMs); - return android::hardware::Status::ok(); - } else { - return android::hardware::details::StatusOf<V1_0::Status, void>(status); - } - } - private: - sp<aidl::IVibrator> mVib; - bool mUnderExternalControl = false; - - Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) { - switch(status.exceptionCode()) { - using android::hardware::Status; - case Status::EX_NONE: return V1_0::Status::OK; - case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE; - case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION; - case Status::EX_TRANSACTION_FAILED: { - return Status::fromStatusT(status.transactionError()); - } - } - return V1_0::Status::UNKNOWN_ERROR; - } - - class CallbackShim : public aidl::BnVibratorCallback { - public: - CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {} - binder::Status onComplete() { - mCb->onComplete(); - return binder::Status::ok(); // oneway, local call - } - private: - sp<V1_4::IVibratorCallback> mCb; - }; -}; - -class VibratorCallback : public V1_4::IVibratorCallback { +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == + static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == + static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == + static_cast<uint8_t>(aidl::EffectStrength::STRONG)); + +static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == + static_cast<uint8_t>(aidl::Effect::CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == + static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == + static_cast<uint8_t>(aidl::Effect::TICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == + static_cast<uint8_t>(aidl::Effect::THUD)); +static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == + static_cast<uint8_t>(aidl::Effect::POP)); +static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) == + static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) == + static_cast<uint8_t>(aidl::Effect::RINGTONE_1)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) == + static_cast<uint8_t>(aidl::Effect::RINGTONE_2)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == + static_cast<uint8_t>(aidl::Effect::RINGTONE_15)); +static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == + static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); + +class VibratorCallback { public: VibratorCallback(JNIEnv *env, jobject vibration) : mVibration(MakeGlobalRefOrDie(env, vibration)) {} @@ -212,47 +87,92 @@ class VibratorCallback : public V1_4::IVibratorCallback { env->DeleteGlobalRef(mVibration); } - Return<void> onComplete() override { + void onComplete() { auto env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(mVibration, sMethodIdOnComplete); - return Void(); } private: jobject mVibration; }; +class AidlVibratorCallback : public aidl::BnVibratorCallback { + public: + AidlVibratorCallback(JNIEnv *env, jobject vibration) : + mCb(env, vibration) {} + + binder::Status onComplete() override { + mCb.onComplete(); + return binder::Status::ok(); // oneway, local call + } + + private: + VibratorCallback mCb; +}; + static constexpr int NUM_TRIES = 2; +template<class R> +inline R NoneStatus() { + using ::android::hardware::Status; + return Status::fromExceptionCode(Status::EX_NONE); +} + +template<> +inline binder::Status NoneStatus() { + using binder::Status; + return Status::fromExceptionCode(Status::EX_NONE); +} + // Creates a Return<R> with STATUS::EX_NULL_POINTER. template<class R> -inline Return<R> NullptrStatus() { +inline R NullptrStatus() { using ::android::hardware::Status; - return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; + return Status::fromExceptionCode(Status::EX_NULL_POINTER); +} + +template<> +inline binder::Status NullptrStatus() { + using binder::Status; + return Status::fromExceptionCode(Status::EX_NULL_POINTER); +} + +template <typename I> +sp<I> getService() { + return I::getService(); +} + +template <> +sp<aidl::IVibrator> getService() { + return waitForVintfService<aidl::IVibrator>(); +} + +template <typename I> +sp<I> tryGetService() { + return I::tryGetService(); +} + +template <> +sp<aidl::IVibrator> tryGetService() { + return checkVintfService<aidl::IVibrator>(); } template <typename I> class HalWrapper { public: static std::unique_ptr<HalWrapper> Create() { - sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>(); - if (aidlVib) { - return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib))); - } - // Assume that if getService returns a nullptr, HAL is not available on the // device. - auto hal = I::getService(); + auto hal = getService<I>(); return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; } // Helper used to transparently deal with the vibrator HAL becoming unavailable. template<class R, class... Args0, class... Args1> - Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) { + R call(R (I::* fn)(Args0...), Args1&&... args1) { // Return<R> doesn't have a default constructor, so make a Return<R> with // STATUS::EX_NONE. - using ::android::hardware::Status; - Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)}; + R ret{NoneStatus<R>()}; // Note that ret is guaranteed to be changed after this loop. for (int i = 0; i < NUM_TRIES; ++i) { @@ -266,12 +186,7 @@ class HalWrapper { ALOGE("Failed to issue command to vibrator HAL. Retrying."); // Restoring connection to the HAL. - sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>(); - if (aidlVib) { - mHal = new VibratorShim(aidlVib); - } else { - mHal = I::tryGetService(); - } + mHal = tryGetService<I>(); } return ret; } @@ -290,7 +205,7 @@ static auto getHal() { } template<class R, class I, class... Args0, class... Args1> -Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) { +R halCall(R (I::* fn)(Args0...), Args1&&... args1) { auto hal = getHal<I>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); } @@ -307,110 +222,192 @@ bool isValidEffect(jlong effect) { static void vibratorInit(JNIEnv *env, jclass clazz) { - halCall(&V1_0::IVibrator::ping).isOk(); + if (auto hal = getHal<aidl::IVibrator>()) { + // IBinder::pingBinder isn't accessible as a pointer function + // but getCapabilities can serve the same purpose + int32_t cap; + hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); + } else { + halCall(&V1_0::IVibrator::ping).isOk(); + } } static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) { - return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE; + bool ok; + + if (auto hal = getHal<aidl::IVibrator>()) { + // IBinder::pingBinder isn't accessible as a pointer function + // but getCapabilities can serve the same purpose + int32_t cap; + ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); + } else { + ok = halCall(&V1_0::IVibrator::ping).isOk(); + } + return ok ? JNI_TRUE : JNI_FALSE; } static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) { - Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); - if (retStatus != Status::OK) { - ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr); + if (!status.isOk()) { + ALOGE("vibratorOn command failed: %s", status.toString8().string()); + } + } else { + Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); + if (retStatus != Status::OK) { + ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); + } } } static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) { - Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); - if (retStatus != Status::OK) { - ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::off); + if (!status.isOk()) { + ALOGE("vibratorOff command failed: %s", status.toString8().string()); + } + } else { + Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); + if (retStatus != Status::OK) { + ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); + } } } static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { - return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); + if (auto hal = getHal<aidl::IVibrator>()) { + int32_t cap = 0; + if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { + return false; + } + return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; + } else { + return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); + } } static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { - Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) - .withDefault(Status::UNKNOWN_ERROR); - if (status != Status::OK) { - ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").", - static_cast<uint32_t>(status)); + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude); + if (!status.isOk()) { + ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string()); + } + } else { + Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) + .withDefault(Status::UNKNOWN_ERROR); + if (status != Status::OK) { + ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").", + static_cast<uint32_t>(status)); + } } } static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { - return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); + if (auto hal = getHal<aidl::IVibrator>()) { + int32_t cap = 0; + if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { + return false; + } + return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; + } else { + return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); + } } static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { - Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) - .withDefault(Status::UNKNOWN_ERROR); - if (status != Status::OK) { - ALOGE("Failed to set vibrator external control (%" PRIu32 ").", - static_cast<uint32_t>(status)); + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled); + if (!status.isOk()) { + ALOGE("Failed to set vibrator external control: %s", status.toString8().string()); + } + } else { + Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) + .withDefault(Status::UNKNOWN_ERROR); + if (status != Status::OK) { + ALOGE("Failed to set vibrator external control (%" PRIu32 ").", + static_cast<uint32_t>(status)); + } } } static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, jobject vibration) { - Status status; - uint32_t lengthMs; - auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { - status = retStatus; - lengthMs = retLengthMs; - }; - EffectStrength effectStrength(static_cast<EffectStrength>(strength)); - - Return<void> ret; - if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) { - sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration); - ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect), - effectStrength, effectCallback, callback); - } else if (isValidEffect<V1_0::Effect>(effect)) { - ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), - effectStrength, callback); - } else if (isValidEffect<Effect_1_1>(effect)) { - ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect), - effectStrength, callback); - } else if (isValidEffect<V1_2::Effect>(effect)) { - ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect), - effectStrength, callback); - } else if (isValidEffect<V1_3::Effect>(effect)) { - ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect), - effectStrength, callback); + if (auto hal = getHal<aidl::IVibrator>()) { + int32_t lengthMs; + sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration); + aidl::Effect effectType(static_cast<aidl::Effect>(strength)); + aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength)); + + auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs); + if (!status.isOk()) { + if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) { + ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 + ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string()); + } + return -1; + } + return lengthMs; } else { - ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")", - static_cast<int32_t>(effect)); - return -1; - } + Status status; + uint32_t lengthMs; + auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { + status = retStatus; + lengthMs = retLengthMs; + }; + EffectStrength effectStrength(static_cast<EffectStrength>(strength)); + + Return<void> ret; + if (isValidEffect<V1_0::Effect>(effect)) { + ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), + effectStrength, callback); + } else if (isValidEffect<Effect_1_1>(effect)) { + ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect), + effectStrength, callback); + } else if (isValidEffect<V1_2::Effect>(effect)) { + ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect), + effectStrength, callback); + } else if (isValidEffect<V1_3::Effect>(effect)) { + ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect), + effectStrength, callback); + } else { + ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")", + static_cast<int32_t>(effect)); + return -1; + } - if (!ret.isOk()) { - ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect)); - return -1; - } + if (!ret.isOk()) { + ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect)); + return -1; + } - if (status == Status::OK) { - return lengthMs; - } else if (status != Status::UNSUPPORTED_OPERATION) { - // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor - // doesn't have a pre-defined waveform to perform for it, so we should just give the - // opportunity to fall back to the framework waveforms. - ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 - ", error=%" PRIu32 ").", static_cast<int64_t>(effect), - static_cast<int32_t>(strength), static_cast<uint32_t>(status)); + if (status == Status::OK) { + return lengthMs; + } else if (status != Status::UNSUPPORTED_OPERATION) { + // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor + // doesn't have a pre-defined waveform to perform for it, so we should just give the + // opportunity to fall back to the framework waveforms. + ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 + ", error=%" PRIu32 ").", static_cast<int64_t>(effect), + static_cast<int32_t>(strength), static_cast<uint32_t>(status)); + } } return -1; } static jlong vibratorGetCapabilities(JNIEnv*, jclass) { - return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0); + if (auto hal = getHal<aidl::IVibrator>()) { + int32_t cap = 0; + if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { + return 0; + } + return cap; + } + + return 0; } static const JNINativeMethod method_table[] = { diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 21bdc43d0d58..3bc28383cf29 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -698,12 +698,6 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { JNIEnv* env = getJniEnv(); uint32_t listSize = getGnssSvInfoListSize(svStatus); - if (listSize > static_cast<uint32_t>( - android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) { - ALOGD("Too many satellites %u. Clamps to %u.", listSize, - static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)); - listSize = static_cast<uint32_t>(android::hardware::gnss::V1_0::GnssMax::SVS_COUNT); - } jintArray svidWithFlagArray = env->NewIntArray(listSize); jfloatArray cn0Array = env->NewFloatArray(listSize); diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java index 69e24063210d..865e3b8cc109 100644 --- a/services/net/java/android/net/NetworkStackClient.java +++ b/services/net/java/android/net/NetworkStackClient.java @@ -103,7 +103,7 @@ public class NetworkStackClient { // checks here should be kept in sync with PermissionUtil. if (caller != Process.SYSTEM_UID && caller != Process.NETWORK_STACK_UID - && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) { + && UserHandle.getAppId(caller) != Process.BLUETOOTH_UID) { throw new SecurityException( "Only the system server should try to bind to the network stack."); } diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java index 975689db5264..be6a31fa949e 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java @@ -32,24 +32,28 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RunWith(JUnit4.class) public class RuleXmlParserTest { @Test public void testXmlStream_validOpenFormula() throws Exception { + Map<String, String> atomicFormulaAttrs = new HashMap<>(); + atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + atomicFormulaAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + atomicFormulaAttrs.put("V", "com.app.test"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -65,17 +69,19 @@ public class RuleXmlParserTest { @Test public void testXmlString_validOpenFormula_notConnector() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -90,22 +96,24 @@ public class RuleXmlParserTest { @Test public void testXmlString_validOpenFormula_andConnector() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); + Map<String, String> appCertificateAttrs = new HashMap<>(); + appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); + appCertificateAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + appCertificateAttrs.put("V", "test_cert"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.AND + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<AF>" - + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>test_cert</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.AND)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -121,22 +129,24 @@ public class RuleXmlParserTest { @Test public void testXmlString_validOpenFormula_orConnector() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); + Map<String, String> appCertificateAttrs = new HashMap<>(); + appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); + appCertificateAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + appCertificateAttrs.put("V", "test_cert"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.OR + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<AF>" - + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>test_cert</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.OR)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -152,17 +162,19 @@ public class RuleXmlParserTest { @Test public void testXmlString_validOpenFormula_differentTagOrder() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<C>" + OpenFormula.NOT + "</C>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -177,22 +189,24 @@ public class RuleXmlParserTest { @Test public void testXmlString_invalidOpenFormula_invalidNumberOfFormulas() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); + Map<String, String> versionCodeAttrs = new HashMap<>(); + versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE)); + versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + versionCodeAttrs.put("V", "1"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<AF>" - + "<K>" + AtomicFormula.VERSION_CODE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>1</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -205,17 +219,19 @@ public class RuleXmlParserTest { @Test public void testXmlString_invalidOpenFormula_invalidOperator() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", "INVALID_OPERATOR"); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>INVALID_OPERATOR</O>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -228,17 +244,19 @@ public class RuleXmlParserTest { @Test public void testXmlString_invalidOpenFormula_invalidEffect() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", "INVALID_EFFECT"), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>INVALID_EFFECT</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -251,37 +269,41 @@ public class RuleXmlParserTest { @Test public void testXmlString_invalidOpenFormula_invalidTags() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlOpenFormula = "<RL>" - + "<R>" - + "<OF>" - + "<InvalidConnector>" + OpenFormula.NOT + "</InvalidConnector>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "InvalidAtomicFormula", + packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); assertExpectException( RuleParseException.class, - /* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidConnector", + /* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidAtomicFormula", () -> xmlParser.parse(ruleXmlOpenFormula)); } @Test public void testXmlString_validAtomicFormula_stringValue() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -296,14 +318,15 @@ public class RuleXmlParserTest { @Test public void testXmlString_validAtomicFormula_integerValue() throws Exception { + Map<String, String> versionCodeAttrs = new HashMap<>(); + versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE)); + versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + versionCodeAttrs.put("V", "1"); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.VERSION_CODE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>1</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -318,14 +341,15 @@ public class RuleXmlParserTest { @Test public void testXmlString_validAtomicFormula_booleanValue() throws Exception { + Map<String, String> preInstalledAttrs = new HashMap<>(); + preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED)); + preInstalledAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + preInstalledAttrs.put("V", "true"); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>true</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -339,15 +363,16 @@ public class RuleXmlParserTest { } @Test - public void testXmlString_validAtomicFormula_differentTagOrder() throws Exception { + public void testXmlString_validAtomicFormula_differentAttributeOrder() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -361,35 +386,37 @@ public class RuleXmlParserTest { } @Test - public void testXmlString_invalidAtomicFormula_invalidTags() throws Exception { + public void testXmlString_invalidAtomicFormula_invalidAttribute() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("BadKey", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<BadKey>" + AtomicFormula.PACKAGE_NAME + "</BadKey>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); assertExpectException( RuleParseException.class, - /* expectedExceptionMessageRegex */ "Found unexpected tag: BadKey", + /* expectedExceptionMessageRegex */ "Attribute not found: K", () -> xmlParser.parse(ruleXmlAtomicFormula)); } @Test public void testXmlString_invalidAtomicFormula() throws Exception { + Map<String, String> packageNameAttrs = new HashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE)); + packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + packageNameAttrs.put("V", "com.app.test"); String ruleXmlAtomicFormula = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.VERSION_CODE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -402,16 +429,18 @@ public class RuleXmlParserTest { @Test public void testXmlString_withNoRuleList() { - String ruleXmlWithNoRuleList = "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + Map<String, String> atomicFormulaAttrs = new HashMap<>(); + atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + atomicFormulaAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + atomicFormulaAttrs.put("V", "com.app.test"); + String ruleXmlWithNoRuleList = generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>"; RuleParser xmlParser = new RuleXmlParser(); @@ -423,16 +452,18 @@ public class RuleXmlParserTest { @Test public void testXmlStream_withNoRuleList() { - String ruleXmlWithNoRuleList = "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>com.app.test</V>" - + "</AF>" + Map<String, String> atomicFormulaAttrs = new HashMap<>(); + atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + atomicFormulaAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + atomicFormulaAttrs.put("V", "com.app.test"); + String ruleXmlWithNoRuleList = generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>"; InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes()); RuleParser xmlParser = new RuleXmlParser(); @@ -442,4 +473,19 @@ public class RuleXmlParserTest { /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag", () -> xmlParser.parse(inputStream)); } + + private String generateTagWithAttribute(String tag, Map<String, String> attributeValues, + boolean closed) { + StringBuilder res = new StringBuilder("<"); + res.append(tag); + for (String attribute : attributeValues.keySet()) { + res.append(" "); + res.append(attribute); + res.append("=\""); + res.append(attributeValues.get(attribute)); + res.append("\""); + } + res.append(closed ? " />" : ">"); + return res.toString(); + } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java index 082fda82499a..a25627155950 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java @@ -36,6 +36,8 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; @RunWith(JUnit4.class) public class RuleXmlSerializerTest { @@ -58,13 +60,14 @@ public class RuleXmlSerializerTest { new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); String expectedRules = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; @@ -81,16 +84,18 @@ public class RuleXmlSerializerTest { "com.app.test"))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); OutputStream outputStream = new ByteArrayOutputStream(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); String expectedRules = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; @@ -107,16 +112,18 @@ public class RuleXmlSerializerTest { new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); String expectedRules = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.NOT + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; @@ -133,20 +140,22 @@ public class RuleXmlSerializerTest { new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); + Map<String, String> appCertificateAttrs = new LinkedHashMap<>(); + appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); + appCertificateAttrs.put("V", "test_cert"); String expectedRules = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.AND + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" - + "<AF>" - + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>" - + "<V>test_cert</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.AND)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; @@ -163,20 +172,22 @@ public class RuleXmlSerializerTest { new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); + Map<String, String> appCertificateAttrs = new LinkedHashMap<>(); + appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); + appCertificateAttrs.put("V", "test_cert"); String expectedRules = "<RL>" - + "<R>" - + "<OF>" - + "<C>" + OpenFormula.OR + "</C>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" - + "<AF>" - + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>" - + "<V>test_cert</V>" - + "</AF>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(OpenFormula.OR)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" - + "<E>" + Rule.DENY + "</E>" + "</R>" + "</RL>"; @@ -191,13 +202,14 @@ public class RuleXmlSerializerTest { new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> packageNameAttrs = new LinkedHashMap<>(); + packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); + packageNameAttrs.put("V", "com.app.test"); String expectedRules = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>" - + "<V>com.app.test</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; @@ -212,14 +224,15 @@ public class RuleXmlSerializerTest { new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> versionCodeAttrs = new LinkedHashMap<>(); + versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE)); + versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ)); + versionCodeAttrs.put("V", "1"); String expectedRules = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.VERSION_CODE + "</K>" - + "<O>" + AtomicFormula.EQ + "</O>" - + "<V>1</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</R>" + "</RL>"; @@ -234,13 +247,14 @@ public class RuleXmlSerializerTest { new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); + Map<String, String> preInstalledAttrs = new LinkedHashMap<>(); + preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED)); + preInstalledAttrs.put("V", "true"); String expectedRules = "<RL>" - + "<R>" - + "<AF>" - + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>" - + "<V>true</V>" - + "</AF>" - + "<E>" + Rule.DENY + "</E>" + + generateTagWithAttribute(/* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + "</R>" + "</RL>"; @@ -261,6 +275,21 @@ public class RuleXmlSerializerTest { () -> xmlSerializer.serialize(Collections.singletonList(rule))); } + private String generateTagWithAttribute(String tag, Map<String, String> attributeValues, + boolean closed) { + StringBuilder res = new StringBuilder("<"); + res.append(tag); + for (String attribute : attributeValues.keySet()) { + res.append(" "); + res.append(attribute); + res.append("=\""); + res.append(attributeValues.get(attribute)); + res.append("\""); + } + res.append(closed ? " />" : ">"); + return res.toString(); + } + private Formula getInvalidFormula() { return new Formula() { @Override diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java new file mode 100644 index 000000000000..03c10f3a86f8 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 20019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.app.IUiModeManager; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.PowerManager; +import android.os.RemoteException; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import com.android.server.twilight.TwilightManager; +import com.android.server.wm.WindowManagerInternal; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.HashSet; +import java.util.Set; + +import static android.app.UiModeManager.MODE_NIGHT_AUTO; +import static android.app.UiModeManager.MODE_NIGHT_NO; +import static android.app.UiModeManager.MODE_NIGHT_YES; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class UiModeManagerServiceTest extends UiServiceTestCase { + private UiModeManagerService mUiManagerService; + private IUiModeManager mService; + @Mock + private ContentResolver mContentResolver; + @Mock + private WindowManagerInternal mWindowManager; + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + TwilightManager mTwilightManager; + @Mock + PowerManager.WakeLock mWakeLock; + private Set<BroadcastReceiver> mScreenOffRecievers; + + @Before + public void setUp() { + mUiManagerService = new UiModeManagerService(mContext, mWindowManager, mWakeLock, + mTwilightManager, true); + mScreenOffRecievers = new HashSet<>(); + mService = mUiManagerService.getService(); + when(mContext.checkCallingOrSelfPermission(anyString())) + .thenReturn(PackageManager.PERMISSION_GRANTED); + when(mContext.getResources()).thenReturn(mResources); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mContext.registerReceiver(any(), any())).then(inv -> { + mScreenOffRecievers.add(inv.getArgument(0)); + return null; + }); + } + + @Test + public void setAutoMode_screenOffRegistered() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_NO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + mService.setNightMode(MODE_NIGHT_AUTO); + verify(mContext).registerReceiver(any(BroadcastReceiver.class), any()); + } + + @Test + public void setAutoMode_screenOffUnRegistered() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_AUTO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + try { + mService.setNightMode(MODE_NIGHT_NO); + } catch (SecurityException e) { /*we should ignore this update config exception*/ } + given(mContext.registerReceiver(any(), any())).willThrow(SecurityException.class); + verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); + } + + @Test + public void setAutoMode_clearCache() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_AUTO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + try { + mService.setNightMode(MODE_NIGHT_NO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + verify(mWindowManager).clearSnapshotCache(); + } + + @Test + public void setNightModeActive_fromNightModeYesToNoWhenFalse() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_YES); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + try { + mService.setNightModeActivated(false); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + assertEquals(MODE_NIGHT_NO, mService.getNightMode()); + } + + @Test + public void setNightModeActive_fromNightModeNoToYesWhenTrue() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_NO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + try { + mService.setNightModeActivated(true); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + assertEquals(MODE_NIGHT_YES, mService.getNightMode()); + } + + @Test + public void setNightModeActive_autoNightModeNoChanges() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_AUTO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + try { + mService.setNightModeActivated(true); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + assertEquals(MODE_NIGHT_AUTO, mService.getNightMode()); + } + + @Test + public void isNightModeActive_nightModeYes() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_YES); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + assertTrue(isNightModeActivated()); + } + + @Test + public void isNightModeActive_nightModeNo() throws RemoteException { + try { + mService.setNightMode(MODE_NIGHT_NO); + } catch (SecurityException e) { /* we should ignore this update config exception*/ } + assertFalse(isNightModeActivated()); + } + + private boolean isNightModeActivated() { + return (mUiManagerService.getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_YES) != 0; + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index bd336ad2494f..1c150969144a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -262,7 +262,6 @@ public class AppWindowTokenTests extends WindowTestsBase { mActivity.setOccludesParent(true); mActivity.setHidden(true); - mActivity.sendingToBottom = true; // Can not specify orientation if app isn't visible even though it occludes parent. assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation()); // Can specify orientation if the current orientation candidate is orientation behind. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 571f214564a0..466dc9bd0088 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -700,6 +701,37 @@ public class DisplayContentTests extends WindowTestsBase { } @Test + public void testAllowsTopmostFullscreenOrientation() { + final DisplayContent dc = createNewDisplay(); + dc.getDisplayRotation().setFixedToUserRotation( + DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED); + + final ActivityStack stack = + new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer) + .setDisplay(dc.mActivityDisplay) + .build(); + doReturn(true).when(stack).isVisible(); + + final ActivityStack freeformStack = + new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer) + .setDisplay(dc.mActivityDisplay) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .build(); + doReturn(true).when(freeformStack).isVisible(); + freeformStack.getTopChild().setBounds(100, 100, 300, 400); + + assertTrue(dc.isStackVisible(WINDOWING_MODE_FREEFORM)); + + freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT); + assertEquals(SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation()); + + stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT); + assertEquals(SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation()); + } + + @Test public void testOnDescendantOrientationRequestChanged() { final DisplayContent dc = createNewDisplay(); dc.getDisplayRotation().setFixedToUserRotation( @@ -872,7 +904,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception { - mWm.mSystemGestureExcludedByPreQStickyImmersive = true; + mWm.mConstants.mSystemGestureExcludedByPreQStickyImmersive = true; final DisplayContent dc = createNewDisplay(); final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java index fa83f85345f0..5fb6f45b400e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java @@ -20,28 +20,23 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFR import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.res.Resources; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; -import android.util.Pair; import androidx.test.filters.SmallTest; import com.android.internal.R; -import com.android.server.wm.HighRefreshRateBlacklist.DeviceConfigInterface; +import com.android.internal.util.Preconditions; +import com.android.server.wm.utils.FakeDeviceConfigInterface; +import org.junit.After; import org.junit.Test; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * Build/Install/Run: @@ -50,67 +45,79 @@ import java.util.concurrent.TimeUnit; @SmallTest @Presubmit public class HighRefreshRateBlacklistTest { + private static final String APP1 = "com.android.sample1"; + private static final String APP2 = "com.android.sample2"; + private static final String APP3 = "com.android.sample3"; + + private HighRefreshRateBlacklist mBlacklist; + + @After + public void tearDown() { + mBlacklist.dispose(); + } @Test public void testDefaultBlacklist() { - final Resources r = createResources("com.android.sample1", "com.android.sample2"); - HighRefreshRateBlacklist blacklist = - new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface()); - assertTrue(blacklist.isBlacklisted("com.android.sample1")); - assertTrue(blacklist.isBlacklisted("com.android.sample2")); - assertFalse(blacklist.isBlacklisted("com.android.sample3")); + final Resources r = createResources(APP1, APP2); + mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig()); + + assertTrue(mBlacklist.isBlacklisted(APP1)); + assertTrue(mBlacklist.isBlacklisted(APP2)); + assertFalse(mBlacklist.isBlacklisted(APP3)); } @Test public void testNoDefaultBlacklist() { final Resources r = createResources(); - HighRefreshRateBlacklist blacklist = - new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface()); - assertFalse(blacklist.isBlacklisted("com.android.sample1")); + mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig()); + + assertFalse(mBlacklist.isBlacklisted(APP1)); } @Test public void testDefaultBlacklistIsOverriddenByDeviceConfig() { - final Resources r = createResources("com.android.sample1"); - final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface(); - config.setBlacklist("com.android.sample2,com.android.sample3"); - HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config); - assertFalse(blacklist.isBlacklisted("com.android.sample1")); - assertTrue(blacklist.isBlacklisted("com.android.sample2")); - assertTrue(blacklist.isBlacklisted("com.android.sample3")); + final Resources r = createResources(APP1); + final FakeDeviceConfig config = new FakeDeviceConfig(); + config.setBlacklist(APP2 + "," + APP3); + mBlacklist = new HighRefreshRateBlacklist(r, config); + + assertFalse(mBlacklist.isBlacklisted(APP1)); + assertTrue(mBlacklist.isBlacklisted(APP2)); + assertTrue(mBlacklist.isBlacklisted(APP3)); } @Test public void testDefaultBlacklistIsOverriddenByEmptyDeviceConfig() { - final Resources r = createResources("com.android.sample1"); - final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface(); + final Resources r = createResources(APP1); + final FakeDeviceConfig config = new FakeDeviceConfig(); config.setBlacklist(""); - HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config); - assertFalse(blacklist.isBlacklisted("com.android.sample1")); + mBlacklist = new HighRefreshRateBlacklist(r, config); + + assertFalse(mBlacklist.isBlacklisted(APP1)); } @Test public void testDefaultBlacklistIsOverriddenByDeviceConfigUpdate() { - final Resources r = createResources("com.android.sample1"); - final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface(); - HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config); + final Resources r = createResources(APP1); + final FakeDeviceConfig config = new FakeDeviceConfig(); + mBlacklist = new HighRefreshRateBlacklist(r, config); // First check that the default blacklist is in effect - assertTrue(blacklist.isBlacklisted("com.android.sample1")); - assertFalse(blacklist.isBlacklisted("com.android.sample2")); - assertFalse(blacklist.isBlacklisted("com.android.sample3")); + assertTrue(mBlacklist.isBlacklisted(APP1)); + assertFalse(mBlacklist.isBlacklisted(APP2)); + assertFalse(mBlacklist.isBlacklisted(APP3)); // Then confirm that the DeviceConfig list has propagated and taken effect. - config.setBlacklist("com.android.sample2,com.android.sample3"); - assertFalse(blacklist.isBlacklisted("com.android.sample1")); - assertTrue(blacklist.isBlacklisted("com.android.sample2")); - assertTrue(blacklist.isBlacklisted("com.android.sample3")); + config.setBlacklist(APP2 + "," + APP3); + assertFalse(mBlacklist.isBlacklisted(APP1)); + assertTrue(mBlacklist.isBlacklisted(APP2)); + assertTrue(mBlacklist.isBlacklisted(APP3)); // Finally make sure we go back to the default list if the DeviceConfig gets deleted. config.setBlacklist(null); - assertTrue(blacklist.isBlacklisted("com.android.sample1")); - assertFalse(blacklist.isBlacklisted("com.android.sample2")); - assertFalse(blacklist.isBlacklisted("com.android.sample3")); + assertTrue(mBlacklist.isBlacklisted(APP1)); + assertFalse(mBlacklist.isBlacklisted(APP2)); + assertFalse(mBlacklist.isBlacklisted(APP3)); } private Resources createResources(String... defaultBlacklist) { @@ -120,64 +127,25 @@ public class HighRefreshRateBlacklistTest { return r; } - - class FakeDeviceConfigInterface implements DeviceConfigInterface { - private List<Pair<DeviceConfig.OnPropertiesChangedListener, Executor>> mListeners = - new ArrayList<>(); - private String mBlacklist; + private static class FakeDeviceConfig extends FakeDeviceConfigInterface { @Override public String getProperty(String namespace, String name) { - if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace) - || !KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) { - throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER " - + "supported."); - } - return mBlacklist; + Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)); + Preconditions.checkArgument(KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)); + return super.getProperty(namespace, name); } @Override public void addOnPropertiesChangedListener(String namespace, Executor executor, DeviceConfig.OnPropertiesChangedListener listener) { - - if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)) { - throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER " - + "supported."); - } - mListeners.add(new Pair<>(listener, executor)); + Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)); + super.addOnPropertiesChangedListener(namespace, executor, listener); } void setBlacklist(String blacklist) { - mBlacklist = blacklist; - CountDownLatch latch = new CountDownLatch(mListeners.size()); - for (Pair<DeviceConfig.OnPropertiesChangedListener, Executor> listenerInfo : - mListeners) { - final Executor executor = listenerInfo.second; - final DeviceConfig.OnPropertiesChangedListener listener = listenerInfo.first; - DeviceConfig.Properties properties = createBlacklistProperties(blacklist); - executor.execute(() -> { - listener.onPropertiesChanged(properties); - latch.countDown(); - }); - } - try { - latch.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to notify all blacklist listeners in time.", e); - } - } - - private DeviceConfig.Properties createBlacklistProperties(final String blacklist) { - DeviceConfig.Properties properties = mock(DeviceConfig.Properties.class); - when(properties.getString(anyString(), any())).thenAnswer(invocation -> { - final Object[] args = invocation.getArguments(); - if (KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(args[0])) { - return blacklist; - } else { - return args[1]; - } - }); - return properties; + putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_HIGH_REFRESH_RATE_BLACKLIST, blacklist); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 562775c2025f..2c34f331e965 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -56,7 +56,6 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.StrictMode; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.view.InputChannel; import android.view.Surface; import android.view.SurfaceControl; @@ -299,10 +298,11 @@ public class SystemServicesTestRule implements TestRule { // Unregister display listener from root to avoid issues with subsequent tests. mContext.getSystemService(DisplayManager.class) .unregisterDisplayListener(mAtmService.mRootActivityContainer); - // ProptertiesChangesListener is registered in the constructor of WindowManagerService to - // a static object, so we need to clean it up in tearDown(), even though we didn't set up - // in tests. - DeviceConfig.removeOnPropertiesChangedListener(mWmService.mPropertiesChangedListener); + // The constructor of WindowManagerService registers WindowManagerConstants and + // HighRefreshRateBlacklist with DeviceConfig. We need to undo that here to avoid + // leaking mWmService. + mWmService.mConstants.dispose(); + mWmService.mHighRefreshRateBlacklist.dispose(); waitUntilWindowManagerHandlersIdle(); // Needs to explicitly dispose current static threads because there could be messages diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java index bebb3ba52bff..f595e0525cc2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java @@ -20,11 +20,17 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static junit.framework.Assert.assertEquals; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import android.app.ActivityManager.TaskSnapshot; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + import org.junit.Before; import org.junit.Test; @@ -39,12 +45,14 @@ import org.junit.Test; public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { private TaskSnapshotCache mCache; + @Mock + TaskSnapshot mSnapshot; @Override @Before public void setUp() { super.setUp(); - + MockitoAnnotations.initMocks(this); mCache = new TaskSnapshotCache(mWm, mLoader); } @@ -110,4 +118,13 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, true /* restoreFromDisk */, false /* reducedResolution */)); } + + @Test + public void testClearCache() { + final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); + mCache.putSnapshot(window.getTask(), mSnapshot); + assertEquals(mSnapshot, mCache.getSnapshot(window.getTask().mTaskId, 0, false, false)); + mCache.clearRunningCache(); + assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0, false, false)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index 58770418413c..f5e65b1385dd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -102,10 +102,7 @@ public class TaskStackTests extends WindowTestsBase { WindowTestUtils.createTestActivityRecord(mDisplayContent); task2.addChild(activity2, 0); activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); - assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation()); - task2.setSendingToBottom(true); - assertEquals(SCREEN_ORIENTATION_LANDSCAPE, stack.getOrientation()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java new file mode 100644 index 000000000000..52100116df53 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE; +import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP; +import static android.provider.DeviceConfig.NAMESPACE_ANDROID; +import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER; + +import static com.android.server.wm.WindowManagerConstants.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.wm.utils.FakeDeviceConfigInterface; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Presubmit +@SmallTest +public class WindowManagerConstantsTest { + + ExecutorService mExecutor; + WindowManagerConstants mConstants; + FakeDeviceConfigInterface mDeviceConfig; + Runnable mUpdateSystemGestureExclusionCallback; + + @Before + public void setUp() throws Exception { + mExecutor = Executors.newSingleThreadExecutor(); + mDeviceConfig = new FakeDeviceConfigInterface(); + mUpdateSystemGestureExclusionCallback = mock(Runnable.class); + mConstants = new WindowManagerConstants(new WindowManagerGlobalLock(), + mUpdateSystemGestureExclusionCallback, mDeviceConfig); + } + + @After + public void tearDown() throws Exception { + mExecutor.shutdown(); + } + + @Test + public void test_constantsAreLoaded_initially() { + mDeviceConfig.putProperty(NAMESPACE_ANDROID, KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, "400"); + mDeviceConfig.putProperty(NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, "true"); + mDeviceConfig.putProperty(NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, "10000"); + + mConstants.start(mExecutor); + + assertEquals(400, mConstants.mSystemGestureExclusionLimitDp); + assertTrue(mConstants.mSystemGestureExcludedByPreQStickyImmersive); + assertEquals(10000, mConstants.mSystemGestureExclusionLogDebounceTimeoutMillis); + } + + @Test + public void test_constantsAreLoaded_afterChange() { + mConstants.start(mExecutor); + + mDeviceConfig.putPropertyAndNotify( + NAMESPACE_ANDROID, KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, "400"); + mDeviceConfig.putPropertyAndNotify(NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, "true"); + mDeviceConfig.putPropertyAndNotify(NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, "10000"); + + assertEquals(400, mConstants.mSystemGestureExclusionLimitDp); + assertTrue(mConstants.mSystemGestureExcludedByPreQStickyImmersive); + assertEquals(10000, mConstants.mSystemGestureExclusionLogDebounceTimeoutMillis); + } + + @Test + public void test_changedGestureExclusionLimit_invokesCallback() { + mConstants.start(mExecutor); + + mDeviceConfig.putPropertyAndNotify( + NAMESPACE_ANDROID, KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, "400"); + + verify(mUpdateSystemGestureExclusionCallback).run(); + } + + @Test + public void test_changedPreQStickyImmersive_invokesCallback() { + mConstants.start(mExecutor); + + mDeviceConfig.putPropertyAndNotify(NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, "true"); + + verify(mUpdateSystemGestureExclusionCallback).run(); + } + + @Test + public void test_minimumExclusionLimitIs_200dp() { + mDeviceConfig.putProperty(NAMESPACE_ANDROID, KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, "20"); + + mConstants.start(mExecutor); + assertEquals(200, mConstants.mSystemGestureExclusionLimitDp); + + mDeviceConfig.putPropertyAndNotify(NAMESPACE_ANDROID, + KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, "21"); + assertEquals(200, mConstants.mSystemGestureExclusionLimitDp); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java b/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java new file mode 100644 index 000000000000..2904a5b73646 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.utils; + +import android.annotation.NonNull; +import android.provider.DeviceConfig; +import android.util.ArrayMap; +import android.util.Pair; + +import com.android.internal.util.Preconditions; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +public class FakeDeviceConfigInterface implements DeviceConfigInterface { + + private Map<String, String> mProperties = new HashMap<>(); + private ArrayMap<DeviceConfig.OnPropertiesChangedListener, Pair<String, Executor>> mListeners = + new ArrayMap<>(); + + public void clearProperties() { + mProperties.clear(); + } + + public void putProperty(String namespace, String key, String value) { + mProperties.put(createCompositeName(namespace, key), value); + } + + public void putPropertyAndNotify(String namespace, String key, String value) { + putProperty(namespace, key, value); + DeviceConfig.Properties properties = makeProperties(namespace, key, value); + CountDownLatch latch = new CountDownLatch(mListeners.size()); + for (int i = 0; i < mListeners.size(); i++) { + if (namespace.equals(mListeners.valueAt(i).first)) { + final int j = i; + mListeners.valueAt(i).second.execute( + () -> { + mListeners.keyAt(j).onPropertiesChanged(properties); + latch.countDown(); + }); + } else { + latch.countDown(); + } + } + boolean success; + try { + success = latch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + success = false; + } + if (!success) { + throw new RuntimeException("Failed to notify all listeners in time."); + } + } + + private DeviceConfig.Properties makeProperties(String namespace, String key, String value) { + try { + final Constructor<DeviceConfig.Properties> ctor = + DeviceConfig.Properties.class.getDeclaredConstructor(String.class, Map.class); + ctor.setAccessible(true); + final HashMap<String, String> keyValueMap = new HashMap<>(); + keyValueMap.put(key, value); + return ctor.newInstance(namespace, keyValueMap); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + @Override + public String getProperty(String namespace, String name) { + return mProperties.get(createCompositeName(namespace, name)); + } + + @Override + public String getString(String namespace, String name, String defaultValue) { + String value = getProperty(namespace, name); + return value != null ? value : defaultValue; + } + + @Override + public int getInt(String namespace, String name, int defaultValue) { + String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + @Override + public long getLong(String namespace, String name, long defaultValue) { + String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + @Override + public boolean getBoolean(String namespace, String name, boolean defaultValue) { + String value = getProperty(namespace, name); + return value != null ? Boolean.parseBoolean(value) : defaultValue; + } + + @Override + public void addOnPropertiesChangedListener(String namespace, Executor executor, + DeviceConfig.OnPropertiesChangedListener listener) { + Pair<String, Executor> oldNamespace = mListeners.get(listener); + if (oldNamespace == null) { + // Brand new listener, add it to the list. + mListeners.put(listener, new Pair<>(namespace, executor)); + } else if (namespace.equals(oldNamespace.first)) { + // Listener is already registered for this namespace, update executor just in case. + mListeners.put(listener, new Pair<>(namespace, executor)); + } else { + // DeviceConfig allows re-registering listeners for different namespaces, but that + // silently unregisters the prior namespace. This likely isn't something the caller + // intended. + throw new IllegalStateException("Listener " + listener + " already registered. This" + + "is technically allowed by DeviceConfig, but likely indicates a logic " + + "error."); + } + } + + @Override + public void removeOnPropertiesChangedListener( + DeviceConfig.OnPropertiesChangedListener listener) { + mListeners.remove(listener); + } + + private static String createCompositeName(@NonNull String namespace, @NonNull String name) { + Preconditions.checkNotNull(namespace); + Preconditions.checkNotNull(name); + return namespace + "/" + name; + } +} diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java index ae924645d3da..bebbbd01fd88 100644 --- a/telecomm/java/android/telecom/DisconnectCause.java +++ b/telecomm/java/android/telecom/DisconnectCause.java @@ -97,6 +97,14 @@ public final class DisconnectCause implements Parcelable { */ public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL"; + /** + * This reason is set when a call is ended in order to place an emergency call when a + * {@link PhoneAccount} doesn't support holding an ongoing call to place an emergency call. This + * reason string should only be associated with the {@link #LOCAL} disconnect code returned from + * {@link #getCode()}. + */ + public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED"; + private int mDisconnectCode; private CharSequence mDisconnectLabel; private CharSequence mDisconnectDescription; diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java index 5fb4e90b9666..5fb4e90b9666 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 46c89d26ad03..8be84a61db76 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -809,7 +809,9 @@ public class CarrierConfigManager { /** * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in * Settings->More->Emergency broadcasts menu even though developer options is turned on. + * @deprecated moved to cellbroadcastreceiver resource show_test_settings */ + @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool"; @@ -1743,6 +1745,15 @@ public class CarrierConfigManager { "allow_emergency_video_calls_bool"; /** + * Flag indicating whether or not an ongoing call will be held when an outgoing emergency call + * is placed. If true, ongoing calls will be put on hold when an emergency call is placed. If + * false, placing an emergency call will trigger the disconnect of all ongoing calls before + * the emergency call is placed. + */ + public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = + "allow_hold_call_during_emergency_bool"; + + /** * Flag indicating whether the carrier supports RCS presence indication for * User Capability Exchange (UCE). When presence is supported, the device should use the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the @@ -3567,6 +3578,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_MMS_USER_AGENT_STRING, ""); sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true); sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0); + sDefaults.putBoolean(KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true); sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false); sDefaults.putBoolean(KEY_USE_RCS_SIP_OPTIONS_BOOL, false); sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false); diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index 85110c22aa18..04ec4b6949af 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -354,6 +354,12 @@ public final class DisconnectCause { */ public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79; + /** + * Indicates that an emergency call was placed, which caused the existing connection to be + * hung up. + */ + public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80; + //********************************************************************************************* // When adding a disconnect type: // 1) Update toString() with the newly added disconnect type. @@ -528,6 +534,8 @@ public final class DisconnectCause { return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE"; case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION"; + case OUTGOING_EMERGENCY_CALL_PLACED: + return "OUTGOING_EMERGENCY_CALL_PLACED"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fe1028b1bd46..60a2cd043887 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7853,8 +7853,8 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi - public boolean isTetherApnRequired() { - return isTetherApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId())); + public boolean isTetheringApnRequired() { + return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId())); } /** @@ -7864,11 +7864,11 @@ public class TelephonyManager { * @return {@code true} if DUN APN is required for tethering. * @hide */ - public boolean isTetherApnRequired(int subId) { + public boolean isTetheringApnRequired(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.isTetherApnRequiredForSubscriber(subId); + return telephony.isTetheringApnRequiredForSubscriber(subId); } catch (RemoteException ex) { Rlog.e(TAG, "hasMatchedTetherApnSetting RemoteException", ex); } catch (NullPointerException ex) { diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 119f890bcb7b..e96d082ca953 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -199,12 +199,19 @@ public class RcsFeature extends ImsFeature { /** @hide*/ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = { + CAPABILITY_TYPE_NONE, CAPABILITY_TYPE_OPTIONS_UCE, CAPABILITY_TYPE_PRESENCE_UCE }) public @interface RcsImsCapabilityFlag {} /** + * Undefined capability type for initialization + * @hide + */ + public static final int CAPABILITY_TYPE_NONE = 0; + + /** * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS. * If not set, this RcsFeature should not service capability requests. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index e96a0787c9af..e895baecab73 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -849,7 +849,7 @@ interface ITelephony { * @return {@code true} if DUN APN is required for tethering. * @hide */ - boolean isTetherApnRequiredForSubscriber(int subId); + boolean isTetheringApnRequiredForSubscriber(int subId); /** * Enables framework IMS and triggers IMS Registration. diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp new file mode 100644 index 000000000000..5e9ef8efc402 --- /dev/null +++ b/tests/PlatformCompatGating/Android.bp @@ -0,0 +1,33 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test { + name: "PlatformCompatGating", + // Only compile source java files in this apk. + srcs: ["src/**/*.java"], + certificate: "platform", + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: [ + "junit", + "android-support-test", + "mockito-target-minus-junit4", + "truth-prebuilt", + "platform-compat-test-rules" + ], +} diff --git a/tests/PlatformCompatGating/AndroidManifest.xml b/tests/PlatformCompatGating/AndroidManifest.xml new file mode 100644 index 000000000000..7f14b83fbc75 --- /dev/null +++ b/tests/PlatformCompatGating/AndroidManifest.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.gating"> + <application android:label="GatingTest"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.tests.gating"/> +</manifest> diff --git a/tests/PlatformCompatGating/AndroidTest.xml b/tests/PlatformCompatGating/AndroidTest.xml new file mode 100644 index 000000000000..c62684837332 --- /dev/null +++ b/tests/PlatformCompatGating/AndroidTest.xml @@ -0,0 +1,30 @@ +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Test compatibility change gating."> + <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="PlatformCompatGating.apk"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/> + <option name="test-suite-tag" value="apct"/> + <option name="test-tag" value="Gating"/> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.tests.gating"/> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java new file mode 100644 index 000000000000..731be8e3d9f0 --- /dev/null +++ b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compat.testing; + +import android.compat.Compatibility; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; + +import com.android.internal.compat.IPlatformCompat; + +/** + * This is a dummy API to test gating + * + * @hide + */ +public class DummyApi { + + public static final long CHANGE_ID = 666013; + public static final long CHANGE_ID_1 = 666014; + public static final long CHANGE_ID_2 = 666015; + public static final long CHANGE_SYSTEM_SERVER = 666016; + + /** + * Dummy method + * @return "A" if change is enabled, "B" otherwise. + */ + public static String dummyFunc() { + if (Compatibility.isChangeEnabled(CHANGE_ID)) { + return "A"; + } + return "B"; + } + + /** + * Dummy combined method + * @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled, + "1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled, + "2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled, + "3" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is enabled. + */ + public static String dummyCombinedFunc() { + if (!Compatibility.isChangeEnabled(CHANGE_ID_1) + && !Compatibility.isChangeEnabled(CHANGE_ID_2)) { + return "0"; + } else if (!Compatibility.isChangeEnabled(CHANGE_ID_1) + && Compatibility.isChangeEnabled(CHANGE_ID_2)) { + return "1"; + } else if (Compatibility.isChangeEnabled(CHANGE_ID_1) + && !Compatibility.isChangeEnabled(CHANGE_ID_2)) { + return "2"; + } + return "3"; + } + + /** + * Dummy api using system server API. + */ + public static boolean dummySystemServer(Context context) { + IPlatformCompat platformCompat = IPlatformCompat.Stub + .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + if (platformCompat == null) { + throw new RuntimeException("Could not obtain IPlatformCompat instance!"); + } + String packageName = context.getPackageName(); + try { + return platformCompat.isChangeEnabledByPackageName(CHANGE_SYSTEM_SERVER, packageName, + context.getUserId()); + } catch (RemoteException e) { + throw new RuntimeException("Could not get change value!", e); + } + } +} diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java new file mode 100644 index 000000000000..dc317f1941c7 --- /dev/null +++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java @@ -0,0 +1,94 @@ +/* + * 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.gating; + +import static com.google.common.truth.Truth.assertThat; + +import android.compat.testing.PlatformCompatChangeRule; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import com.android.compat.testing.DummyApi; + +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; + +/** + * Tests for platform compatibility change gating. + */ +@RunWith(AndroidJUnit4.class) +public class PlatformCompatGatingTest { + + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + + @Test + @EnableCompatChanges({DummyApi.CHANGE_ID}) + public void testDummyGatingPositive() { + assertThat(DummyApi.dummyFunc()).isEqualTo("A"); + } + + @Test + @DisableCompatChanges({DummyApi.CHANGE_ID}) + public void testDummyGatingNegative() { + assertThat(DummyApi.dummyFunc()).isEqualTo("B"); + } + + @Test + @DisableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2}) + public void testDummyGatingCombined0() { + assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("0"); + } + + @Test + @DisableCompatChanges({DummyApi.CHANGE_ID_1}) + @EnableCompatChanges({DummyApi.CHANGE_ID_2}) + public void testDummyGatingCombined1() { + assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("1"); + } + + @Test + @EnableCompatChanges({DummyApi.CHANGE_ID_1}) + @DisableCompatChanges({DummyApi.CHANGE_ID_2}) + public void testDummyGatingCombined2() { + assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("2"); + } + + @Test + @EnableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2}) + public void testDummyGatingCombined3() { + assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("3"); + } + + @Test + @EnableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER}) + public void testDummyGatingPositiveSystemServer() { + assertThat( + DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isTrue(); + } + + @Test + @DisableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER}) + public void testDummyGatingNegativeSystemServer() { + assertThat( + DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isFalse(); + } +} diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp new file mode 100644 index 000000000000..8211ef523ee7 --- /dev/null +++ b/tests/PlatformCompatGating/test-rules/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +java_library { + name: "platform-compat-test-rules", + srcs: ["src/**/*.java"], + static_libs: [ + "junit", + "android-support-test", + "truth-prebuilt", + "core-compat-test-rules" + ], +}
\ No newline at end of file diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java new file mode 100644 index 000000000000..932ec643d478 --- /dev/null +++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.compat.testing; + +import android.app.Instrumentation; +import android.compat.Compatibility; +import android.compat.Compatibility.ChangeConfig; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.support.test.InstrumentationRegistry; + +import com.android.internal.compat.CompatibilityChangeConfig; +import com.android.internal.compat.IPlatformCompat; + +import libcore.junit.util.compat.CoreCompatChangeRule; + +import org.junit.runners.model.Statement; + +/** + * Allows tests to specify the which change to disable. + * + * <p>To use add the following to the test class. It will only change the behavior of a test method + * if it is annotated with + * {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or + * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges}. + * </p> + * <pre> + * @Rule + * public TestRule compatChangeRule = new PlatformCompatChangeRule(); + * </pre> + * + * <p>Each test method that needs to disable a specific change needs to be annotated + * with {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or + * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges} specifying the change + * id. e.g.: + * </p> + * <pre> + * @Test + * @DisableCompatChanges({42}) + * public void testAsIfChange42Disabled() { + * // check behavior + * } + * + * @Test + * @EnableCompatChanges({42}) + * public void testAsIfChange42Enabled() { + * // check behavior + * + * </pre> + */ +public class PlatformCompatChangeRule extends CoreCompatChangeRule { + + @Override + protected Statement createStatementForConfig(final Statement statement, ChangeConfig config) { + return new CompatChangeStatement(statement, config); + } + + + private static class CompatChangeStatement extends Statement { + private final Statement mTestStatement; + private final ChangeConfig mConfig; + + private CompatChangeStatement(Statement testStatement, ChangeConfig config) { + this.mTestStatement = testStatement; + this.mConfig = config; + } + + @Override + public void evaluate() throws Throwable { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + String packageName = instrumentation.getTargetContext().getPackageName(); + IPlatformCompat platformCompat = IPlatformCompat.Stub + .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + if (platformCompat == null) { + throw new IllegalStateException("Could not get IPlatformCompat service!"); + } + Compatibility.setOverrides(mConfig); + try { + platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig), + packageName); + try { + mTestStatement.evaluate(); + } finally { + platformCompat.clearOverridesForTest(packageName); + } + } catch (RemoteException e) { + throw new RuntimeException("Could not call IPlatformCompat binder method!", e); + } finally { + Compatibility.clearOverrides(); + } + } + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 61f37fd6c7e2..aad2f3da40f2 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,6 +20,9 @@ import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL; +import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; +import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; @@ -28,6 +31,7 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; +import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK; @@ -145,6 +149,7 @@ import android.net.MatchAllNetworkSpecifier; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkFactory; +import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; @@ -244,6 +249,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; import kotlin.reflect.KClass; @@ -330,6 +336,9 @@ public class ConnectivityServiceTest { private class MockContext extends BroadcastInterceptingContext { private final MockContentResolver mContentResolver; + // Contains all registered receivers since this object was created. Useful to clear + // them when needed, as BroadcastInterceptingContext does not provide this facility. + private final List<BroadcastReceiver> mRegisteredReceivers = new ArrayList<>(); @Spy private Resources mResources; private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>(); @@ -343,6 +352,7 @@ public class ConnectivityServiceTest { "wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true", "mobile_mms,2,0,2,60000,true", + "mobile_supl,3,0,2,60000,true", }); when(mResources.getStringArray( @@ -410,6 +420,19 @@ public class ConnectivityServiceTest { // make sure the code does not rely on unexpected permissions. super.enforceCallingOrSelfPermission(permission, message); } + + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { + mRegisteredReceivers.add(receiver); + return super.registerReceiver(receiver, filter); + } + + public void clearRegisteredReceivers() { + // super.unregisterReceiver is a no-op for receivers that are not registered (because + // they haven't been registered or because they have already been unregistered). + // For the same reason, don't bother clearing mRegisteredReceivers. + for (final BroadcastReceiver rcv : mRegisteredReceivers) unregisterReceiver(rcv); + } } private void waitForIdle() { @@ -438,7 +461,7 @@ public class ConnectivityServiceTest { } // Bring up a network that we can use to send messages to ConnectivityService. - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); waitFor(cv); @@ -458,7 +481,7 @@ public class ConnectivityServiceTest { @Ignore public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception { // Bring up a network that we can use to send messages to ConnectivityService. - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); waitFor(cv); @@ -1227,17 +1250,26 @@ public class ConnectivityServiceTest { * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION * broadcasts are received. */ - private ConditionVariable waitForConnectivityBroadcasts(final int count) { + private ConditionVariable registerConnectivityBroadcast(final int count) { + return registerConnectivityBroadcastThat(count, intent -> true); + } + + private ConditionVariable registerConnectivityBroadcastThat(final int count, + @NonNull final Predicate<Intent> filter) { final ConditionVariable cv = new ConditionVariable(); - mServiceContext.registerReceiver(new BroadcastReceiver() { + final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION); + intentFilter.addAction(CONNECTIVITY_ACTION_SUPL); + final BroadcastReceiver receiver = new BroadcastReceiver() { private int remaining = count; public void onReceive(Context context, Intent intent) { + if (!filter.test(intent)) return; if (--remaining == 0) { cv.open(); mServiceContext.unregisterReceiver(this); } } - }, new IntentFilter(CONNECTIVITY_ACTION)); + }; + mServiceContext.registerReceiver(receiver, intentFilter); return cv; } @@ -1258,6 +1290,75 @@ public class ConnectivityServiceTest { } @Test + public void testNetworkFeature() throws Exception { + // Connect the cell agent and wait for the connected broadcast. + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL); + final ConditionVariable cv1 = registerConnectivityBroadcastThat(1, + intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE); + mCellNetworkAgent.connect(true); + waitFor(cv1); + + // Build legacy request for SUPL. + final NetworkCapabilities legacyCaps = new NetworkCapabilities(); + legacyCaps.addTransportType(TRANSPORT_CELLULAR); + legacyCaps.addCapability(NET_CAPABILITY_SUPL); + final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL, + ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST); + + // Send request and check that the legacy broadcast for SUPL is sent correctly. + final TestNetworkCallback callback = new TestNetworkCallback(); + final ConditionVariable cv2 = registerConnectivityBroadcastThat(1, + intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL); + mCm.requestNetwork(legacyRequest, callback); + callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent); + waitFor(cv2); + + // File another request, withdraw it and make sure no broadcast is sent + final ConditionVariable cv3 = registerConnectivityBroadcast(1); + final TestNetworkCallback callback2 = new TestNetworkCallback(); + mCm.requestNetwork(legacyRequest, callback2); + callback2.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent); + mCm.unregisterNetworkCallback(callback2); + assertFalse(cv3.block(800)); // 800ms long enough to at least flake if this is sent + // As the broadcast did not fire, the receiver was not unregistered. Do this now. + mServiceContext.clearRegisteredReceivers(); + + // Withdraw the request and check that the broadcast for disconnection is sent. + final ConditionVariable cv4 = registerConnectivityBroadcastThat(1, intent -> + !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected() + && intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL); + mCm.unregisterNetworkCallback(callback); + waitFor(cv4); + + // Re-file the request and expect the connected broadcast again + final ConditionVariable cv5 = registerConnectivityBroadcastThat(1, + intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL); + final TestNetworkCallback callback3 = new TestNetworkCallback(); + mCm.requestNetwork(legacyRequest, callback3); + callback3.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent); + waitFor(cv5); + + // Disconnect the network and expect two disconnected broadcasts, one for SUPL and one + // for mobile. Use a small hack to check that both have been sent, but the order is + // not contractual. + final AtomicBoolean vanillaAction = new AtomicBoolean(false); + final AtomicBoolean suplAction = new AtomicBoolean(false); + final ConditionVariable cv6 = registerConnectivityBroadcastThat(2, intent -> { + if (intent.getAction().equals(CONNECTIVITY_ACTION)) { + vanillaAction.set(true); + } else if (intent.getAction().equals(CONNECTIVITY_ACTION_SUPL)) { + suplAction.set(true); + } + return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected(); + }); + mCellNetworkAgent.disconnect(); + waitFor(cv6); + assertTrue(vanillaAction.get()); + assertTrue(suplAction.get()); + } + + @Test public void testLingering() throws Exception { verifyNoNetwork(); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); @@ -1265,7 +1366,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetworkInfo()); assertNull(mCm.getActiveNetwork()); // Test bringing up validated cellular. - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); @@ -1275,7 +1376,7 @@ public class ConnectivityServiceTest { assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) || mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork())); // Test bringing up validated WiFi. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1292,7 +1393,7 @@ public class ConnectivityServiceTest { assertLength(1, mCm.getAllNetworks()); assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork()); // Test WiFi disconnect. - cv = waitForConnectivityBroadcasts(1); + cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.disconnect(); waitFor(cv); verifyNoNetwork(); @@ -1302,7 +1403,7 @@ public class ConnectivityServiceTest { public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception { // Test bringing up unvalidated WiFi mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1317,17 +1418,17 @@ public class ConnectivityServiceTest { verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test cellular disconnect. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mCellNetworkAgent.disconnect(); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi disconnect. - cv = waitForConnectivityBroadcasts(1); + cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.disconnect(); waitFor(cv); verifyNoNetwork(); @@ -1337,23 +1438,23 @@ public class ConnectivityServiceTest { public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception { // Test bringing up unvalidated cellular. mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi disconnect. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.disconnect(); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test cellular disconnect. - cv = waitForConnectivityBroadcasts(1); + cv = registerConnectivityBroadcast(1); mCellNetworkAgent.disconnect(); waitFor(cv); verifyNoNetwork(); @@ -1363,7 +1464,7 @@ public class ConnectivityServiceTest { public void testUnlingeringDoesNotValidate() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1371,14 +1472,14 @@ public class ConnectivityServiceTest { NET_CAPABILITY_VALIDATED)); // Test bringing up validated cellular. mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); // Test cellular disconnect. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mCellNetworkAgent.disconnect(); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1391,23 +1492,23 @@ public class ConnectivityServiceTest { public void testCellularOutscoresWeakWifi() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test WiFi getting really weak. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.adjustScore(-11); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test WiFi restoring signal strength. - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.adjustScore(11); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1427,7 +1528,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.expectDisconnected(); // Test bringing up validated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - final ConditionVariable cv = waitForConnectivityBroadcasts(1); + final ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -1446,18 +1547,18 @@ public class ConnectivityServiceTest { public void testCellularFallback() throws Exception { // Test bringing up validated cellular. mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test bringing up validated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Reevaluate WiFi (it'll instantly fail DNS). - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork()); @@ -1467,7 +1568,7 @@ public class ConnectivityServiceTest { NET_CAPABILITY_VALIDATED)); verifyActiveNetwork(TRANSPORT_CELLULAR); // Reevaluate cellular (it'll instantly fail DNS). - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); mCm.reportBadNetwork(mCellNetworkAgent.getNetwork()); @@ -1484,18 +1585,18 @@ public class ConnectivityServiceTest { public void testWiFiFallback() throws Exception { // Test bringing up unvalidated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); // Test bringing up validated cellular. mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mCellNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); // Reevaluate cellular (it'll instantly fail DNS). - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability( NET_CAPABILITY_VALIDATED)); mCm.reportBadNetwork(mCellNetworkAgent.getNetwork()); @@ -1570,7 +1671,7 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); // Test unvalidated networks - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); @@ -1585,7 +1686,7 @@ public class ConnectivityServiceTest { assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -1594,7 +1695,7 @@ public class ConnectivityServiceTest { waitFor(cv); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - cv = waitForConnectivityBroadcasts(2); + cv = registerConnectivityBroadcast(2); mWiFiNetworkAgent.disconnect(); genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); @@ -1602,7 +1703,7 @@ public class ConnectivityServiceTest { waitFor(cv); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); - cv = waitForConnectivityBroadcasts(1); + cv = registerConnectivityBroadcast(1); mCellNetworkAgent.disconnect(); genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); @@ -2192,7 +2293,7 @@ public class ConnectivityServiceTest { // Test bringing up validated WiFi. mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - final ConditionVariable cv = waitForConnectivityBroadcasts(1); + final ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -2220,7 +2321,7 @@ public class ConnectivityServiceTest { public void testMMSonCell() throws Exception { // Test bringing up cellular without MMS mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mCellNetworkAgent.connect(false); waitFor(cv); verifyActiveNetwork(TRANSPORT_CELLULAR); @@ -3679,7 +3780,7 @@ public class ConnectivityServiceTest { } mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); mWiFiNetworkAgent.connect(true); waitFor(cv); verifyActiveNetwork(TRANSPORT_WIFI); @@ -4212,7 +4313,7 @@ public class ConnectivityServiceTest { assertNotPinnedToWifi(); // Disconnect cell and wifi. - ConditionVariable cv = waitForConnectivityBroadcasts(3); // cell down, wifi up, wifi down. + ConditionVariable cv = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down. mCellNetworkAgent.disconnect(); mWiFiNetworkAgent.disconnect(); waitFor(cv); @@ -4225,7 +4326,7 @@ public class ConnectivityServiceTest { assertPinnedToWifiWithWifiDefault(); // ... and is maintained even when that network is no longer the default. - cv = waitForConnectivityBroadcasts(1); + cv = registerConnectivityBroadcast(1); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mCellNetworkAgent.connect(true); waitFor(cv); @@ -4326,7 +4427,7 @@ public class ConnectivityServiceTest { @Test public void testNetworkInfoOfTypeNone() throws Exception { - ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1); + ConditionVariable broadcastCV = registerConnectivityBroadcast(1); verifyNoNetwork(); TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE); @@ -5778,7 +5879,7 @@ public class ConnectivityServiceTest { .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId)); // Disconnect wifi - ConditionVariable cv = waitForConnectivityBroadcasts(1); + ConditionVariable cv = registerConnectivityBroadcast(1); reset(mNetworkManagementService); mWiFiNetworkAgent.disconnect(); waitFor(cv); diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt index f045369459c9..42d4cf3c382b 100644 --- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt +++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt @@ -18,6 +18,7 @@ package com.android.server import android.net.ConnectivityManager.TYPE_ETHERNET import android.net.ConnectivityManager.TYPE_MOBILE +import android.net.ConnectivityManager.TYPE_MOBILE_SUPL import android.net.ConnectivityManager.TYPE_WIFI import android.net.ConnectivityManager.TYPE_WIMAX import android.net.NetworkInfo.DetailedState.CONNECTED @@ -46,7 +47,7 @@ const val UNSUPPORTED_TYPE = TYPE_WIMAX @RunWith(AndroidJUnit4::class) @SmallTest class LegacyTypeTrackerTest { - private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET) + private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL) private val mMockService = mock(ConnectivityService::class.java).apply { doReturn(false).`when`(this).isDefaultNetwork(any()) @@ -70,6 +71,26 @@ class LegacyTypeTrackerTest { } @Test + fun testSupl() { + val mobileNai = mock(NetworkAgentInfo::class.java) + mTracker.add(TYPE_MOBILE, mobileNai) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE) + reset(mMockService) + mTracker.add(TYPE_MOBILE_SUPL, mobileNai) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL) + reset(mMockService) + mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL) + reset(mMockService) + mTracker.add(TYPE_MOBILE_SUPL, mobileNai) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL) + reset(mMockService) + mTracker.remove(mobileNai, false) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE) + } + + @Test fun testAddNetwork() { val mobileNai = mock(NetworkAgentInfo::class.java) val wifiNai = mock(NetworkAgentInfo::class.java) diff --git a/tools/genprotos.sh b/tools/genprotos.sh deleted file mode 100755 index f901c9f588b6..000000000000 --- a/tools/genprotos.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can -# end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to -# the way sbox rewrites the command. See b/70221552. - -set -e - -location_aprotoc=$1 -location_protoc=$2 -location_soong_zip=$3 -genDir=$4 -depfile=$5 -in=$6 -out=$7 - -mkdir -p ${genDir}/${in} && \ - ${location_aprotoc} --plugin=${location_protoc} \ - --dependency_out=${depfile} \ - --javastream_out=${genDir}/${in} \ - -Iexternal/protobuf/src \ - -I . \ - ${in} && \ - ${location_soong_zip} -jar -o ${out} -C ${genDir}/${in} -D ${genDir}/${in} diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp index 0e33fddcde07..1e96234543c8 100644 --- a/tools/processors/unsupportedappusage/Android.bp +++ b/tools/processors/unsupportedappusage/Android.bp @@ -1,11 +1,6 @@ -java_plugin { - name: "unsupportedappusage-annotation-processor", - processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor", - - java_resources: [ - "META-INF/**/*", - ], +java_library_host { + name: "unsupportedappusage-annotation-processor-lib", srcs: [ "src/**/*.java", ], @@ -22,6 +17,18 @@ java_plugin { "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", ], }, +} + +java_plugin { + name: "unsupportedappusage-annotation-processor", + processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor", + + java_resources: [ + "META-INF/**/*", + ], + static_libs: [ + "unsupportedappusage-annotation-processor-lib" + ], use_tools_jar: true, } diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java index 5a5703ed520c..65fc733fa364 100644 --- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java +++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java @@ -101,14 +101,20 @@ public class SignatureBuilder { private String getClassSignature(TypeElement clazz) { StringBuilder sb = new StringBuilder("L"); for (Element enclosing : getEnclosingElements(clazz)) { - if (enclosing.getKind() == PACKAGE) { - sb.append(((PackageElement) enclosing) - .getQualifiedName() - .toString() - .replace('.', '/')); - sb.append('/'); - } else { - sb.append(enclosing.getSimpleName()).append('$'); + switch (enclosing.getKind()) { + case MODULE: + // ignore this. + break; + case PACKAGE: + sb.append(((PackageElement) enclosing) + .getQualifiedName() + .toString() + .replace('.', '/')); + sb.append('/'); + break; + default: + sb.append(enclosing.getSimpleName()).append('$'); + break; } } diff --git a/cmds/idmap/Android.bp b/tools/processors/unsupportedappusage/test/Android.bp index ae5d74a47000..49ea3d4bbc96 100644 --- a/cmds/idmap/Android.bp +++ b/tools/processors/unsupportedappusage/test/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C) 2012 The Android Open Source Project +// Copyright (C) 2019 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. @@ -12,27 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_binary { - name: "idmap", +java_test_host { + name: "unsupportedappusage-processor-test", - srcs: [ - "idmap.cpp", - "create.cpp", - "scan.cpp", - "inspect.cpp", - ], - - shared_libs: [ - "liblog", - "libutils", - "libandroidfw", - "libcutils", - ], + srcs: ["src/**/*.java"], - cflags: [ - "-Wall", - "-Werror", - "-Wunused", - "-Wunreachable-code", + static_libs: [ + "libjavac", + "unsupportedappusage-annotation-processor-lib", + "truth-host-prebuilt", + "mockito-host", + "junit-host", + "objenesis", ], } diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java new file mode 100644 index 000000000000..23db99e81194 --- /dev/null +++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.processor.unsupportedappusage; + +import com.google.common.base.Splitter; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CsvReader { + + private final Splitter mSplitter; + private final List<String> mColumns; + private final List<Map<String, String>> mContents; + + public CsvReader(InputStream in) throws IOException { + mSplitter = Splitter.on(","); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + mColumns = mSplitter.splitToList(br.readLine()); + mContents = new ArrayList<>(); + String line = br.readLine(); + while (line != null) { + List<String> contents = mSplitter.splitToList(line); + Map<String, String> contentMap = new HashMap<>(); + for (int i = 0; i < Math.min(contents.size(), mColumns.size()); ++i) { + contentMap.put(mColumns.get(i), contents.get(i)); + } + mContents.add(contentMap); + line = br.readLine(); + } + br.close(); + } + + public List<String> getColumns() { + return mColumns; + } + + public List<Map<String, String>> getContents() { + return mContents; + } +} diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java new file mode 100644 index 000000000000..012e88f17924 --- /dev/null +++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.processor.unsupportedappusage; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.javac.Javac; + +import com.google.common.base.Joiner; + +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Map; + +public class UnsupportedAppUsageProcessorTest { + + private Javac mJavac; + + @Before + public void setup() throws IOException { + mJavac = new Javac(); + mJavac.addSource("dalvik.annotation.compat.UnsupportedAppUsage", Joiner.on('\n').join( + "package dalvik.annotation.compat;", + "public @interface UnsupportedAppUsage {", + " String expectedSignature() default \"\";\n", + " String someProperty() default \"\";", + "}")); + } + + private CsvReader compileAndReadCsv() throws IOException { + mJavac.compileWithAnnotationProcessor(new UnsupportedAppUsageProcessor()); + return new CsvReader( + mJavac.getOutputFile("unsupportedappusage/unsupportedappusage_index.csv")); + } + + @Test + public void testSignatureFormat() throws Exception { + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", + "import dalvik.annotation.compat.UnsupportedAppUsage;", + "public class Class {", + " @UnsupportedAppUsage", + " public void method() {}", + "}")); + assertThat(compileAndReadCsv().getContents().get(0)).containsEntry( + "signature", "La/b/Class;->method()V" + ); + } + + @Test + public void testSourcePosition() throws Exception { + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", // 1 + "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2 + "public class Class {", // 3 + " @UnsupportedAppUsage", // 4 + " public void method() {}", // 5 + "}")); + Map<String, String> row = compileAndReadCsv().getContents().get(0); + assertThat(row).containsEntry("startline", "4"); + assertThat(row).containsEntry("startcol", "3"); + assertThat(row).containsEntry("endline", "4"); + assertThat(row).containsEntry("endcol", "23"); + } + + @Test + public void testAnnotationProperties() throws Exception { + mJavac.addSource("a.b.Class", Joiner.on('\n').join( + "package a.b;", // 1 + "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2 + "public class Class {", // 3 + " @UnsupportedAppUsage(someProperty=\"value\")", // 4 + " public void method() {}", // 5 + "}")); + assertThat(compileAndReadCsv().getContents().get(0)).containsEntry( + "properties", "someProperty=%22value%22"); + } + + +} |