diff options
258 files changed, 11189 insertions, 3614 deletions
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 1d3ac6a9f14f..1a10753d7bcb 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -2079,9 +2079,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - StatsLogEventWrapper e = new StatsLogEventWrapper(StatsLog.APP_OPS, elapsedNanos, - wallClockNanos); - for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) { final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx); final int uid = uidOps.getUid(); @@ -2089,6 +2086,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx); for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) { final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx); + StatsLogEventWrapper e = new StatsLogEventWrapper(StatsLog.APP_OPS, + elapsedNanos, wallClockNanos); + e.writeInt(uid); e.writeString(packageOps.getPackageName()); e.writeInt(op.getOpCode()); diff --git a/api/current.txt b/api/current.txt index 231495fa02c1..3ce043c89b65 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11908,6 +11908,7 @@ package android.content.pm { field public static final int SIGNATURE_NO_MATCH = -3; // 0xfffffffd field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc + field public static final int SYNCHRONOUS = 2; // 0x2 field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff @@ -23133,10 +23134,10 @@ package android.location { method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent); method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle); method public void setTestProviderEnabled(@NonNull String, boolean); method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location); @@ -43171,6 +43172,7 @@ package android.telecom { field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED"; field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS"; field public static final int STATE_ACTIVE = 4; // 0x4 + field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc field public static final int STATE_CONNECTING = 9; // 0x9 field public static final int STATE_DIALING = 1; // 0x1 field public static final int STATE_DISCONNECTED = 7; // 0x7 @@ -43180,6 +43182,7 @@ package android.telecom { field public static final int STATE_PULLING_CALL = 11; // 0xb field public static final int STATE_RINGING = 2; // 0x2 field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8 + field public static final int STATE_SIMULATED_RINGING = 13; // 0xd } public abstract static class Call.Callback { diff --git a/api/system-current.txt b/api/system-current.txt index 7dfe90f023fb..6f4cb0f1a30d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3431,9 +3431,9 @@ package android.location { method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); @@ -6361,6 +6361,7 @@ package android.service.autofill { method public android.os.IBinder onBind(android.content.Intent); method @Nullable public float[][] onCalculateScores(@NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @Nullable String, @Nullable android.os.Bundle, @Nullable java.util.Map, @Nullable java.util.Map); method @Deprecated @Nullable public float[][] onGetScores(@Nullable String, @Nullable android.os.Bundle, @NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>); + field public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE"; field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService"; @@ -6967,6 +6968,8 @@ package android.telecom { public final class Call { method @Deprecated public void addListener(android.telecom.Call.Listener); + method public void enterBackgroundAudioProcessing(); + method public void exitBackgroundAudioProcessing(boolean); method @Deprecated public void removeListener(android.telecom.Call.Listener); field @Deprecated public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8 } @@ -6975,6 +6978,10 @@ package android.telecom { ctor @Deprecated public Call.Listener(); } + public static class CallScreeningService.CallResponse.Builder { + method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean); + } + public abstract class Conference extends android.telecom.Conferenceable { method @Deprecated public final android.telecom.AudioState getAudioState(); method @Deprecated public final long getConnectTimeMillis(); @@ -8239,7 +8246,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping(); method public static long getMaxNumberVerificationTimeoutMillis(); - method @NonNull public String getNetworkCountryIso(int); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); diff --git a/api/test-current.txt b/api/test-current.txt index f500ed9003d8..3dfd62e11622 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1093,9 +1093,9 @@ package android.location { method @NonNull public String[] getBackgroundThrottlingWhitelist(); method @NonNull public String[] getIgnoreSettingsWhitelist(); method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); } @@ -2481,6 +2481,7 @@ package android.service.autofill { public abstract class AutofillFieldClassificationService extends android.app.Service { ctor public AutofillFieldClassificationService(); method public android.os.IBinder onBind(android.content.Intent); + field public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE"; field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService"; @@ -2771,10 +2772,19 @@ package android.service.quicksettings { package android.telecom { + public final class Call { + method public void enterBackgroundAudioProcessing(); + method public void exitBackgroundAudioProcessing(boolean); + } + public final class CallAudioState implements android.os.Parcelable { ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>); } + public static class CallScreeningService.CallResponse.Builder { + method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean); + } + public abstract class Conference extends android.telecom.Conferenceable { method public android.telecom.Connection getPrimaryConnection(); } @@ -2919,7 +2929,7 @@ package android.telephony { method public int checkCarrierPrivilegesForPackage(String); method public int getCarrierIdListVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); - method @NonNull public String getNetworkCountryIso(int); + method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); @@ -2933,6 +2943,14 @@ package android.telephony { } +package android.telephony.emergency { + + public final class EmergencyNumber implements java.lang.Comparable<android.telephony.emergency.EmergencyNumber> android.os.Parcelable { + field public static final int EMERGENCY_NUMBER_SOURCE_TEST = 32; // 0x20 + } + +} + package android.telephony.mbms { public static class DownloadRequest.Builder { diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index 053b7bc9afa3..d0530f2d344e 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -178,6 +178,17 @@ Result<Unit> Scan(const std::vector<std::string>& args) { continue; } + // Note that conditional property enablement/exclusion only applies if + // the attribute is present. In its absence, all overlays are presumed enabled. + if (!overlay_info->requiredSystemPropertyName.empty() + && !overlay_info->requiredSystemPropertyValue.empty()) { + // if property set & equal to value, then include overlay - otherwise skip + if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") + != overlay_info->requiredSystemPropertyValue) { + continue; + } + } + std::vector<std::string> fulfilled_policies; if (!override_policies.empty()) { fulfilled_policies = override_policies; diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index 8797a788dd1d..9a0c2abced5a 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -30,6 +30,8 @@ namespace android::idmap2::utils { struct OverlayManifestInfo { std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes) std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes) + std::string requiredSystemPropertyName; // NOLINT(misc-non-private-member-variables-in-classes) + std::string requiredSystemPropertyValue; // NOLINT(misc-non-private-member-variables-in-classes) bool is_static; // NOLINT(misc-non-private-member-variables-in-classes) int priority = -1; // NOLINT(misc-non-private-member-variables-in-classes) }; diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp index 71ba3f0f1ac2..dce83e35978d 100644 --- a/cmds/idmap2/libidmap2/ResourceUtils.cpp +++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp @@ -103,6 +103,16 @@ Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path, info.priority = std::stoi(iter->second); } + iter = tag->find("requiredSystemPropertyName"); + if (iter != tag->end()) { + info.requiredSystemPropertyName = iter->second; + } + + iter = tag->find("requiredSystemPropertyValue"); + if (iter != tag->end()) { + info.requiredSystemPropertyValue = iter->second; + } + return info; } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index c79b0cab35c6..cb2732561b56 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -138,6 +138,7 @@ cc_defaults { "libprotoutil", "libservices", "libstatslog", + "libstatssocket", "libsysutils", "libtimestats_proto", "libutils", diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp index bbdb5405ca05..d38b87f046e0 100644 --- a/cmds/statsd/src/external/GpuStatsPuller.cpp +++ b/cmds/statsd/src/external/GpuStatsPuller.cpp @@ -92,9 +92,15 @@ static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService, android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs()); if (!event->write(info.appPackageName)) return false; if (!event->write((int64_t)info.driverVersionCode)) return false; - if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false; - if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false; - if (!event->write(int64VectorToProtoByteString(info.angleDriverLoadingTime))) return false; + if (!event->writeBytes(int64VectorToProtoByteString(info.glDriverLoadingTime))) { + return false; + } + if (!event->writeBytes(int64VectorToProtoByteString(info.vkDriverLoadingTime))) { + return false; + } + if (!event->writeBytes(int64VectorToProtoByteString(info.angleDriverLoadingTime))) { + return false; + } if (!event->write(info.cpuVulkanInUse)) return false; if (!event->write(info.falsePrerotation)) return false; event->init(); diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 0ade53118d77..fd19c9d61f87 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -332,6 +332,13 @@ bool LogEvent::write(float value) { return false; } +bool LogEvent::writeBytes(const string& value) { + if (mContext) { + return android_log_write_char_array(mContext, value.c_str(), value.length()) >= 0; + } + return false; +} + bool LogEvent::writeKeyValuePairs(int32_t uid, const std::map<int32_t, int32_t>& int_map, const std::map<int32_t, int64_t>& long_map, diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 531ce299beef..f1f45a2d3bc7 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -21,9 +21,9 @@ #include <android/frameworks/stats/1.0/types.h> #include <android/os/StatsLogEventWrapper.h> #include <android/util/ProtoOutputStream.h> -#include <log/log_event_list.h> #include <log/log_read.h> #include <private/android_logger.h> +#include <stats_event_list.h> #include <utils/Errors.h> #include <string> @@ -157,6 +157,7 @@ public: bool write(float value); bool write(const std::vector<AttributionNodeInternal>& nodes); bool write(const AttributionNodeInternal& node); + bool writeBytes(const std::string& value); bool writeKeyValuePairs(int32_t uid, const std::map<int32_t, int32_t>& int_map, const std::map<int32_t, int64_t>& long_map, diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 504ee22f72e4..0743480bf4ee 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -582,7 +582,7 @@ TEST(LogEventTest, TestBinaryFieldAtom) { event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS); event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW); event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS); - event1.write(extension_str); + event1.writeBytes(extension_str); event1.init(); ProtoOutputStream proto; @@ -621,7 +621,7 @@ TEST(LogEventTest, TestBinaryFieldAtom_empty) { event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS); event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW); event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS); - event1.write(extension_str); + event1.writeBytes(extension_str); event1.init(); ProtoOutputStream proto; diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java index b37ee74b100c..c9f069d62003 100644 --- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java +++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java @@ -78,6 +78,8 @@ public final class Telecom extends BaseCommand { private static final String COMMAND_SET_SIM_COUNT = "set-sim-count"; private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config"; private static final String COMMAND_GET_MAX_PHONES = "get-max-phones"; + private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER = + "set-test-emergency-phone-account-package-filter"; private ComponentName mComponent; private String mAccountId; @@ -91,7 +93,10 @@ public final class Telecom extends BaseCommand { + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n" + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n" + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n" - + "usage: telecom set-user-selected-outgoing-phone-account <COMPONENT> <ID> " + + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>" + + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION" + + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n" + + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> " + "<USER_SN>\n" + "usage: telecom set-test-call-redirection-app <PACKAGE>\n" + "usage: telecom set-test-call-screening-app <PACKAGE>\n" @@ -108,6 +113,7 @@ public final class Telecom extends BaseCommand { + "usage: telecom set-sim-count <COUNT>\n" + "usage: telecom get-sim-config\n" + "usage: telecom get-max-phones\n" + + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n" + "\n" + "telecom set-phone-account-enabled: Enables the given phone account, if it has" + " already been registered with Telecom.\n" @@ -121,6 +127,8 @@ public final class Telecom extends BaseCommand { + "telecom get-default-dialer: Displays the current default dialer.\n" + "\n" + "telecom get-system-dialer: Displays the current system dialer.\n" + + "telecom set-system-dialer: Set the override system dialer to the given" + + " component. To remove the override, send \"default\"\n" + "\n" + "telecom wait-on-handlers: Wait until all handlers finish their work.\n" + "\n" @@ -131,6 +139,10 @@ public final class Telecom extends BaseCommand { + " or \"\" for single SIM\n" + "\n" + "telecom get-max-phones: Get the max supported phones from the modem.\n" + + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a" + + " package name that will be used for test emergency calls. To clear," + + " send an empty package name. Real emergency calls will still be placed" + + " over Telephony.\n" ); } @@ -219,6 +231,9 @@ public final class Telecom extends BaseCommand { case COMMAND_GET_MAX_PHONES: runGetMaxPhones(); break; + case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER: + runSetEmergencyPhoneAccountPackageFilter(); + break; default: Log.w(this, "onRun: unknown command: %s", command); throw new IllegalArgumentException ("unknown command '" + command + "'"); @@ -245,19 +260,31 @@ public final class Telecom extends BaseCommand { } private void runRegisterSimPhoneAccount() throws RemoteException { + boolean isEmergencyAccount = false; + String opt; + while ((opt = nextOption()) != null) { + switch (opt) { + case "-e": { + isEmergencyAccount = true; + break; + } + } + } final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs(); final String label = nextArgRequired(); final String address = nextArgRequired(); + int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER + | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION + | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0); PhoneAccount account = PhoneAccount.builder( handle, label) - .setAddress(Uri.parse(address)) - .setSubscriptionAddress(Uri.parse(address)) - .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | - PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) - .setShortDescription(label) - .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) - .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) - .build(); + .setAddress(Uri.parse(address)) + .setSubscriptionAddress(Uri.parse(address)) + .setCapabilities(capabilities) + .setShortDescription(label) + .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) + .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) + .build(); mTelecomService.registerPhoneAccount(account); System.out.println("Success - " + handle + " registered."); } @@ -309,9 +336,11 @@ public final class Telecom extends BaseCommand { } private void runSetSystemDialer() throws RemoteException { - final String packageName = nextArg(); - mTelecomService.setSystemDialerPackage(packageName.equals("default") ? null : packageName); - System.out.println("Success - " + packageName + " set as override system dialer."); + final String flatComponentName = nextArg(); + final ComponentName componentName = (flatComponentName.equals("default") + ? null : parseComponentName(flatComponentName)); + mTelecomService.setSystemDialer(componentName); + System.out.println("Success - " + componentName + " set as override system dialer."); } private void runGetDefaultDialer() throws RemoteException { @@ -355,6 +384,18 @@ public final class Telecom extends BaseCommand { } } + private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException { + String packageName = mArgs.getNextArg(); + if (TextUtils.isEmpty(packageName)) { + mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null); + System.out.println("Success - filter cleared"); + } else { + mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName); + System.out.println("Success = filter set to " + packageName); + } + + } + private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException { if (TextUtils.isEmpty(mArgs.peekNextArg())) { return null; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index cf36032e8a05..03300e44f9fb 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -76,7 +76,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; import android.os.StrictMode; -import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.text.Selection; @@ -7866,13 +7865,10 @@ public class Activity extends ContextThemeWrapper mFragments.dispatchStart(); mFragments.reportLoaderStart(); + // Warn app developers if the dynamic linker logged anything during startup. boolean isAppDebuggable = (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - - // This property is set for all non-user builds except final release - boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1; - - if (isAppDebuggable || isDlwarningEnabled) { + if (isAppDebuggable) { String dlwarning = getDlWarning(); if (dlwarning != null) { String appName = getApplicationInfo().loadLabel(getPackageManager()) diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index e8918285777b..b56c00e44d3f 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Insets; import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; @@ -101,6 +102,8 @@ public class ActivityView extends ViewGroup { private Insets mForwardedInsets; + private float mCornerRadius; + public ActivityView(Context context) { this(context, null /* attrs */); } @@ -204,6 +207,45 @@ public class ActivityView extends ViewGroup { } /** + * @hide + */ + public float getCornerRadius() { + return mSurfaceView.getCornerRadius(); + } + + /** + * Control whether the surface is clipped to the same bounds as the View. If true, then + * the bounds set by {@link #setSurfaceClipBounds(Rect)} are applied to the surface as + * window-crop. + * + * @param clippingEnabled whether to enable surface clipping + * @hide + */ + public void setSurfaceClippingEnabled(boolean clippingEnabled) { + mSurfaceView.setEnableSurfaceClipping(clippingEnabled); + } + + /** + * Sets an area on the contained surface to which it will be clipped + * when it is drawn. Setting the value to null will remove the clip bounds + * and the surface will draw normally, using its full bounds. + * + * @param clipBounds The rectangular area, in the local coordinates of + * this view, to which future drawing operations will be clipped. + * @hide + */ + public void setSurfaceClipBounds(Rect clipBounds) { + mSurfaceView.setClipBounds(clipBounds); + } + + /** + * @hide + */ + public boolean getSurfaceClipBounds(Rect outRect) { + return mSurfaceView.getClipBounds(outRect); + } + + /** * Launch a new activity into this container. * <p>Activity resolved by the provided {@link Intent} must have * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl index d8cea2860aa8..6d790b381ace 100644 --- a/core/java/android/app/role/IRoleManager.aidl +++ b/core/java/android/app/role/IRoleManager.aidl @@ -19,7 +19,6 @@ package android.app.role; import android.app.role.IOnRoleHoldersChangedListener; import android.os.Bundle; import android.os.RemoteCallback; -import android.telephony.IFinancialSmsCallback; /** * @hide @@ -55,9 +54,4 @@ interface IRoleManager { List<String> getHeldRolesFromController(in String packageName); String getDefaultSmsPackage(int userId); - - /** - * Get filtered SMS messages for financial app. - */ - void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 802c1a0ae6d5..08817e05e0a5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3301,7 +3301,7 @@ public abstract class Context { * <dt> {@link #VIBRATOR_SERVICE} ("vibrator") * <dd> A {@link android.os.Vibrator} for interacting with the vibrator * hardware. - * <dt> {@link #CONNECTIVITY_SERVICE} ("connection") + * <dt> {@link #CONNECTIVITY_SERVICE} ("connectivity") * <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for * handling management of network connections. * <dt> {@link #IPSEC_SERVICE} ("ipsec") diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index fafb56d20ba0..fd14d235a044 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -917,8 +917,9 @@ public abstract class PackageManager { public static final int INSTALL_DRY_RUN = 0x00800000; /** @hide */ - @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { - DONT_KILL_APP + @IntDef(flag = true, value = { + DONT_KILL_APP, + SYNCHRONOUS }) @Retention(RetentionPolicy.SOURCE) public @interface EnabledFlags {} @@ -931,6 +932,14 @@ public abstract class PackageManager { */ public static final int DONT_KILL_APP = 0x00000001; + /** + * Flag parameter for + * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate + * that the given user's package restrictions state will be serialised to disk after the + * component state has been updated. + */ + public static final int SYNCHRONOUS = 0x00000002; + /** @hide */ @IntDef(prefix = { "INSTALL_REASON_" }, value = { INSTALL_REASON_UNKNOWN, diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index df652f190d04..9f0bade9bd29 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -187,6 +187,18 @@ public class UserInfo implements Parcelable { @UnsupportedAppUsage public boolean guestToRemove; + /** + * This is used to optimize the creation of an user, i.e. OEMs might choose to pre-create a + * number of users at the first boot, so the actual creation later is faster. + * + * <p>A {@code preCreated} user is not a real user yet, so it should not show up on regular + * user operations (other than user creation per se). + * + * <p>Once the pre-created is used to create a "real" user later on, {@code preCreate} is set to + * {@code false}. + */ + public boolean preCreated; + @UnsupportedAppUsage public UserInfo(int id, String name, int flags) { this(id, name, null, flags); @@ -214,6 +226,13 @@ public class UserInfo implements Parcelable { @UnsupportedAppUsage public boolean isGuest() { + return isGuest(flags); + } + + /** + * Checks if the flag denotes a guest user. + */ + public static boolean isGuest(@UserInfoFlag int flags) { return (flags & FLAG_GUEST) == FLAG_GUEST; } @@ -224,6 +243,13 @@ public class UserInfo implements Parcelable { @UnsupportedAppUsage public boolean isManagedProfile() { + return isManagedProfile(flags); + } + + /** + * Checks if the flag denotes a managed profile. + */ + public static boolean isManagedProfile(@UserInfoFlag int flags) { return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE; } @@ -315,6 +341,7 @@ public class UserInfo implements Parcelable { lastLoggedInTime = orig.lastLoggedInTime; lastLoggedInFingerprint = orig.lastLoggedInFingerprint; partial = orig.partial; + preCreated = orig.preCreated; profileGroupId = orig.profileGroupId; restrictedProfileParentId = orig.restrictedProfileParentId; guestToRemove = orig.guestToRemove; @@ -339,6 +366,8 @@ public class UserInfo implements Parcelable { return "UserInfo[id=" + id + ", name=" + name + ", flags=" + flagsToString(flags) + + (preCreated ? " (pre-created)" : "") + + (partial ? " (partial)" : "") + "]"; } @@ -362,9 +391,10 @@ public class UserInfo implements Parcelable { dest.writeLong(creationTime); dest.writeLong(lastLoggedInTime); dest.writeString(lastLoggedInFingerprint); - dest.writeInt(partial ? 1 : 0); + dest.writeBoolean(partial); + dest.writeBoolean(preCreated); dest.writeInt(profileGroupId); - dest.writeInt(guestToRemove ? 1 : 0); + dest.writeBoolean(guestToRemove); dest.writeInt(restrictedProfileParentId); dest.writeInt(profileBadge); } @@ -389,9 +419,10 @@ public class UserInfo implements Parcelable { creationTime = source.readLong(); lastLoggedInTime = source.readLong(); lastLoggedInFingerprint = source.readString(); - partial = source.readInt() != 0; + partial = source.readBoolean(); + preCreated = source.readBoolean(); profileGroupId = source.readInt(); - guestToRemove = source.readInt() != 0; + guestToRemove = source.readBoolean(); restrictedProfileParentId = source.readInt(); profileBadge = source.readInt(); } diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 0daf30f25d59..638d81b2f635 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -76,6 +76,9 @@ interface IInputManager { // Registers a tablet mode change listener void registerTabletModeChangedListener(ITabletModeChangedListener listener); + // Queries whether the device's microphone is muted by switch + int isMicMuted(); + // Input device vibrator control. void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token); void cancelVibrate(int deviceId, IBinder token); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 2a59be28a937..0c0f248e3222 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -520,6 +520,22 @@ public final class InputManager { } /** + * Queries whether the device's microphone is muted + * + * @return The mic mute switch state which is one of {@link #SWITCH_STATE_UNKNOWN}, + * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}. + * @hide + */ + @SwitchState + public int isMicMuted() { + try { + return mIm.isMicMuted(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Gets information about all supported keyboard layouts. * <p> * The input manager consults the built-in keyboard layouts as well diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java index cc2fe65dcb7e..20fa7538e2d5 100644 --- a/core/java/android/hardware/location/ContextHubClientCallback.java +++ b/core/java/android/hardware/location/ContextHubClientCallback.java @@ -66,7 +66,9 @@ public class ContextHubClientCallback { public void onNanoAppAborted(ContextHubClient client, long nanoAppId, int abortCode) {} /** - * Callback invoked when a nanoapp is loaded at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically loaded at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. This callback is not invoked for a + * nanoapp that is loaded internally by CHRE (e.g. nanoapps that are preloaded by the system). * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been loaded @@ -74,7 +76,8 @@ public class ContextHubClientCallback { public void onNanoAppLoaded(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is unloaded from the attached Context Hub. + * Callback invoked when a nanoapp is dynamically unloaded from the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been unloaded @@ -82,7 +85,8 @@ public class ContextHubClientCallback { public void onNanoAppUnloaded(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is enabled at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically enabled at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been enabled @@ -90,7 +94,8 @@ public class ContextHubClientCallback { public void onNanoAppEnabled(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is disabled at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically disabled at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been disabled diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 08c9eea6e012..43336682e45f 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -60,6 +60,9 @@ public class UsbDevice implements Parcelable { private final int mClass; private final int mSubclass; private final int mProtocol; + private final boolean mHasAudioPlayback; + private final boolean mHasAudioCapture; + /** All interfaces on the device. Initialized on first call to getInterfaceList */ @UnsupportedAppUsage @@ -73,7 +76,8 @@ public class UsbDevice implements Parcelable { private UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, - @NonNull IUsbSerialReader serialNumberReader) { + @NonNull IUsbSerialReader serialNumberReader, + boolean hasAudioPlayback, boolean hasAudioCapture) { mName = Preconditions.checkNotNull(name); mVendorId = vendorId; mProductId = productId; @@ -85,6 +89,8 @@ public class UsbDevice implements Parcelable { mVersion = Preconditions.checkStringNotEmpty(version); mConfigurations = Preconditions.checkArrayElementsNotNull(configurations, "configurations"); mSerialNumberReader = Preconditions.checkNotNull(serialNumberReader); + mHasAudioPlayback = hasAudioPlayback; + mHasAudioCapture = hasAudioCapture; // Make sure the binder belongs to the system if (ActivityThread.isSystem()) { @@ -214,6 +220,16 @@ public class UsbDevice implements Parcelable { return mConfigurations.length; } + /** @hide */ + public boolean getHasAudioPlayback() { + return mHasAudioPlayback; + } + + /** @hide */ + public boolean getHasAudioCapture() { + return mHasAudioCapture; + } + /** * Returns the {@link UsbConfiguration} at the given index. * @@ -286,12 +302,14 @@ public class UsbDevice implements Parcelable { @Override public String toString() { - StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + - ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + - ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + - ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + - ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader - + ",mConfigurations=["); + StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + + ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + + ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader + + ", mHasAudioPlayback=" + mHasAudioPlayback + + ", mHasAudioCapture=" + mHasAudioCapture + + ", mConfigurations=["); for (int i = 0; i < mConfigurations.length; i++) { builder.append("\n"); builder.append(mConfigurations[i].toString()); @@ -316,9 +334,13 @@ public class UsbDevice implements Parcelable { IUsbSerialReader.Stub.asInterface(in.readStrongBinder()); UsbConfiguration[] configurations = in.readParcelableArray( UsbConfiguration.class.getClassLoader(), UsbConfiguration.class); + // Capabilities + boolean hasAudioPlayback = in.readInt() == 1; + boolean hasAudioCapture = in.readInt() == 1; UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, - manufacturerName, productName, version, configurations, - serialNumberReader); + manufacturerName, productName, version, configurations, serialNumberReader, + hasAudioPlayback, hasAudioCapture); + return device; } @@ -343,6 +365,8 @@ public class UsbDevice implements Parcelable { parcel.writeString(mVersion); parcel.writeStrongBinder(mSerialNumberReader.asBinder()); parcel.writeParcelableArray(mConfigurations, 0); + parcel.writeInt(mHasAudioPlayback ? 1 : 0); + parcel.writeInt(mHasAudioCapture ? 1 : 0); } public static int getDeviceId(String name) { @@ -370,6 +394,8 @@ public class UsbDevice implements Parcelable { private final @Nullable String mProductName; private final @NonNull String mVersion; private final @NonNull UsbConfiguration[] mConfigurations; + private final boolean mHasAudioPlayback; + private final boolean mHasAudioCapture; // Temporary storage for serial number. Serial number reader need to be wrapped in a // IUsbSerialReader as they might be used as PII. @@ -378,7 +404,8 @@ public class UsbDevice implements Parcelable { public Builder(@NonNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, - @Nullable String serialNumber) { + @Nullable String serialNumber, + boolean hasAudioPlayback, boolean hasAudioCapture) { mName = Preconditions.checkNotNull(name); mVendorId = vendorId; mProductId = productId; @@ -390,6 +417,8 @@ public class UsbDevice implements Parcelable { mVersion = Preconditions.checkStringNotEmpty(version); mConfigurations = configurations; this.serialNumber = serialNumber; + mHasAudioPlayback = hasAudioPlayback; + mHasAudioCapture = hasAudioCapture; } /** @@ -401,7 +430,8 @@ public class UsbDevice implements Parcelable { */ public UsbDevice build(@NonNull IUsbSerialReader serialReader) { return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol, - mManufacturerName, mProductName, mVersion, mConfigurations, serialReader); + mManufacturerName, mProductName, mVersion, mConfigurations, serialReader, + mHasAudioPlayback, mHasAudioCapture); } } } diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 3cc28197503a..bc32df42ea4f 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -278,11 +278,13 @@ public final class Debug /** @hide */ public static final int OTHER_DALVIK_OTHER_ACCOUNTING = 22; /** @hide */ - public static final int OTHER_DALVIK_OTHER_CODE_CACHE = 23; + public static final int OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE = 23; /** @hide */ - public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 24; + public static final int OTHER_DALVIK_OTHER_APP_CODE_CACHE = 24; /** @hide */ - public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 25; + public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 25; + /** @hide */ + public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 26; /** @hide */ public static final int OTHER_DVK_STAT_DALVIK_OTHER_START = OTHER_DALVIK_OTHER_LINEARALLOC - NUM_OTHER_STATS; @@ -292,11 +294,11 @@ public final class Debug // Dex subsections (Boot vdex, App dex, and App vdex). /** @hide */ - public static final int OTHER_DEX_BOOT_VDEX = 26; + public static final int OTHER_DEX_BOOT_VDEX = 27; /** @hide */ - public static final int OTHER_DEX_APP_DEX = 27; + public static final int OTHER_DEX_APP_DEX = 28; /** @hide */ - public static final int OTHER_DEX_APP_VDEX = 28; + public static final int OTHER_DEX_APP_VDEX = 29; /** @hide */ public static final int OTHER_DVK_STAT_DEX_START = OTHER_DEX_BOOT_VDEX - NUM_OTHER_STATS; /** @hide */ @@ -304,9 +306,9 @@ public final class Debug // Art subsections (App image, boot image). /** @hide */ - public static final int OTHER_ART_APP = 29; + public static final int OTHER_ART_APP = 30; /** @hide */ - public static final int OTHER_ART_BOOT = 30; + public static final int OTHER_ART_BOOT = 31; /** @hide */ public static final int OTHER_DVK_STAT_ART_START = OTHER_ART_APP - NUM_OTHER_STATS; /** @hide */ @@ -314,7 +316,7 @@ public final class Debug /** @hide */ @UnsupportedAppUsage - public static final int NUM_DVK_STATS = 14; + public static final int NUM_DVK_STATS = OTHER_ART_BOOT + 1 - OTHER_DALVIK_NORMAL; /** @hide */ public static final int NUM_CATEGORIES = 9; @@ -540,7 +542,8 @@ public final class Debug case OTHER_DALVIK_NON_MOVING: return ".NonMoving"; case OTHER_DALVIK_OTHER_LINEARALLOC: return ".LinearAlloc"; case OTHER_DALVIK_OTHER_ACCOUNTING: return ".GC"; - case OTHER_DALVIK_OTHER_CODE_CACHE: return ".JITCache"; + case OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE: return ".ZygoteJIT"; + case OTHER_DALVIK_OTHER_APP_CODE_CACHE: return ".AppJIT"; case OTHER_DALVIK_OTHER_COMPILER_METADATA: return ".CompilerMetadata"; case OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE: return ".IndirectRef"; case OTHER_DEX_BOOT_VDEX: return ".Boot vdex"; @@ -722,7 +725,9 @@ public final class Debug + getOtherPrivate(OTHER_APK) + getOtherPrivate(OTHER_TTF) + getOtherPrivate(OTHER_DEX) - + getOtherPrivate(OTHER_OAT); + + getOtherPrivate(OTHER_OAT) + + getOtherPrivate(OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE) + + getOtherPrivate(OTHER_DALVIK_OTHER_APP_CODE_CACHE); } /** @@ -813,7 +818,9 @@ public final class Debug + getOtherRss(OTHER_APK) + getOtherRss(OTHER_TTF) + getOtherRss(OTHER_DEX) - + getOtherRss(OTHER_OAT); + + getOtherRss(OTHER_OAT) + + getOtherRss(OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE) + + getOtherRss(OTHER_DALVIK_OTHER_APP_CODE_CACHE); } /** diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 63641e538b8e..c30491a3965c 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -41,6 +41,7 @@ interface IUserManager { */ UserInfo createUser(in String name, int flags); + UserInfo preCreateUser(int flags); UserInfo createProfileForUser(in String name, int flags, int userHandle, in String[] disallowedPackages); UserInfo createRestrictedProfile(String name, int parentUserHandle); @@ -53,7 +54,7 @@ interface IUserManager { void setUserIcon(int userHandle, in Bitmap icon); ParcelFileDescriptor getUserIcon(int userHandle); UserInfo getPrimaryUser(); - List<UserInfo> getUsers(boolean excludeDying); + List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated); List<UserInfo> getProfiles(int userHandle, boolean enabledOnly); int[] getProfileIds(int userId, boolean enabledOnly); boolean canAddMoreManagedProfiles(int userHandle, boolean allowedToRemoveOne); @@ -92,6 +93,7 @@ interface IUserManager { boolean someUserHasSeedAccount(in String accountName, in String accountType); boolean isManagedProfile(int userId); boolean isDemoUser(int userId); + boolean isPreCreated(int userId); UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle, in String[] disallowedPackages); boolean isUserUnlockingOrUnlocked(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index af574da084f0..3296f11298c8 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -37,6 +37,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.UserInfo; +import android.content.pm.UserInfo.UserInfoFlag; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; @@ -2013,18 +2014,20 @@ public class UserManager { /** * Creates a user with the specified name and options. For non-admin users, default user - * restrictions are going to be applied. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * restrictions will be applied. + * + * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * * @param name the user's name - * @param flags flags that identify the type of user and other properties. + * @param flags UserInfo flags that identify the type of user and other properties. * @see UserInfo * - * @return the UserInfo object for the created user, or null if the user could not be created. + * @return the UserInfo object for the created user, or {@code null} if the user could not be + * created. * @hide */ @UnsupportedAppUsage - public UserInfo createUser(String name, int flags) { + public @Nullable UserInfo createUser(@Nullable String name, @UserInfoFlag int flags) { UserInfo user = null; try { user = mService.createUser(name, flags); @@ -2041,6 +2044,36 @@ public class UserManager { } /** + * Pre-creates a user with the specified name and options. For non-admin users, default user + * restrictions will be applied. + * + * <p>This method can be used by OEMs to "warm" up the user creation by pre-creating some users + * at the first boot, so they when the "real" user is created (for example, + * by {@link #createUser(String, int)} or {@link #createGuest(Context, String)}), it takes + * less time. + * + * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * + * @param flags UserInfo flags that identify the type of user and other properties. + * @see UserInfo + * + * @return the UserInfo object for the created user, or {@code null} if the user could not be + * created. + * + * @throw {@link IllegalArgumentException} if {@code flags} contains + * {@link UserInfo#FLAG_MANAGED_PROFILE}. + * + * @hide + */ + public @Nullable UserInfo preCreateUser(@UserInfoFlag int flags) { + try { + return mService.preCreateUser(flags); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Creates a guest user and configures it. * @param context an application context * @param name the name to set for the user @@ -2356,15 +2389,26 @@ public class UserManager { /** * Returns information for all users on this device, including ones marked for deletion. * To retrieve only users that are alive, use {@link #getUsers(boolean)}. - * <p> - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * * @return the list of users that exist on the device. * @hide */ @UnsupportedAppUsage + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public List<UserInfo> getUsers() { + return getUsers(/* excludeDying= */ false); + } + + /** + * Returns information for all users on this device, based on the filtering parameters. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, + boolean excludePreCreated) { try { - return mService.getUsers(false); + return mService.getUsers(excludePartial, excludeDying, excludePreCreated); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -2380,16 +2424,12 @@ public class UserManager { @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean excludeDying) { - try { - List<UserInfo> users = mService.getUsers(excludeDying); - long[] result = new long[users.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = users.get(i).serialNumber; - } - return result; - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); + List<UserInfo> users = getUsers(excludeDying); + long[] result = new long[users.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = users.get(i).serialNumber; } + return result; } /** @@ -2773,11 +2813,8 @@ public class UserManager { */ @UnsupportedAppUsage public @NonNull List<UserInfo> getUsers(boolean excludeDying) { - try { - return mService.getUsers(excludeDying); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + return getUsers(/*excludePartial= */ true, excludeDying, + /* excludePreCreated= */ true); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 9a3a7cea42dd..907eae87bcb2 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -758,6 +758,7 @@ public class ZygoteProcess { ZygoteState state = openZygoteSocketIfNeeded(abi); state.mZygoteOutputWriter.write("1\n--boot-completed\n"); state.mZygoteOutputWriter.flush(); + state.mZygoteInputStream.readInt(); } } catch (Exception ex) { throw new RuntimeException("Failed to inform zygote of boot_completed", ex); diff --git a/core/java/android/os/telephony/TelephonyRegistryManager.java b/core/java/android/os/telephony/TelephonyRegistryManager.java index 5c49cb6f60aa..133233124b70 100644 --- a/core/java/android/os/telephony/TelephonyRegistryManager.java +++ b/core/java/android/os/telephony/TelephonyRegistryManager.java @@ -21,13 +21,13 @@ import android.net.NetworkCapabilities; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; -import android.telephony.Annotation; import android.telephony.Annotation.ApnType; import android.telephony.Annotation.CallState; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.DataFailureCause; import android.telephony.Annotation.DataState; import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation.PreciseCallStates; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; @@ -35,7 +35,6 @@ import android.telephony.CallQuality; import android.telephony.CellInfo; import android.telephony.DisconnectCause; import android.telephony.PhoneCapability; -import android.telephony.PreciseCallState.State; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; @@ -466,8 +465,10 @@ public class TelephonyRegistryManager { * * @hide */ - public void notifyPreciseCallState(int subId, int slotIndex, @State int ringCallPreciseState, - @State int foregroundCallPreciseState, @State int backgroundCallPreciseState) { + public void notifyPreciseCallState(int subId, int slotIndex, + @PreciseCallStates int ringCallPreciseState, + @PreciseCallStates int foregroundCallPreciseState, + @PreciseCallStates int backgroundCallPreciseState) { try { sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState, foregroundCallPreciseState, backgroundCallPreciseState); diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index 320dcec675cc..28842a7fa1d7 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -93,6 +93,13 @@ public abstract class AutofillFieldClassificationService extends Service { */ public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; + /** + * Field classification algorithm that compares a credit card string to known last four digits. + * + * <p>Service implementation must provide this algorithm.</p> + */ + public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; + /** {@hide} **/ public static final String EXTRA_SCORES = "scores"; diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index f34f9e6d5ce8..4b872d3ad758 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -73,6 +73,14 @@ oneway interface IWindow { */ void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls); + /** + * Called when a set of insets source window should be shown by policy. + * + * @param types internal inset types (WindowInsets.Type.InsetType) to show + * @param fromIme true if this request originated from IME (InputMethodService). + */ + void showInsets(int types, boolean fromIme); + void moved(int newX, int newY); void dispatchAppVisibility(boolean visible); void dispatchGetNewSurface(); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 49e8800a36c6..35cfe9e591cf 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -644,4 +644,16 @@ interface IWindowManager * Enables/disables SurfaceFlinger layer tracing. */ void setLayerTracing(boolean enabled); + + /** + * Mirrors a specified display. The root of the mirrored hierarchy will be stored in + * outSurfaceControl. + * Requires the ACCESS_SURFACE_FLINGER permission. + * + * @param displayId The id of the display to mirror + * @param outSurfaceControl The SurfaceControl for the root of the mirrored hierarchy. + * + * @return true if the display was successfully mirrored. + */ + boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c798d85f0fea..5a8636d85a08 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -224,7 +224,7 @@ public class InsetsController implements WindowInsetsController { show(types, false /* fromIme */); } - private void show(@InsetType int types, boolean fromIme) { + void show(@InsetType int types, boolean fromIme) { // TODO: Support a ResultReceiver for IME. // TODO(b/123718661): Make show() work for multi-session IME. int typesReady = 0; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 6639fbf9551e..b685cf098b33 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -91,7 +91,7 @@ public final class SurfaceControl implements Parcelable { boolean captureSecureLayers); private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken, long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects); - + private static native long nativeMirrorSurface(long mirrorOfObject); private static native long nativeCreateTransaction(); private static native long nativeGetNativeTransactionFinalizer(); private static native void nativeApplyTransaction(long transactionObj, boolean sync); @@ -2034,6 +2034,28 @@ public final class SurfaceControl implements Parcelable { return nativeSetDisplayBrightness(displayToken, brightness); } + /** + * Creates a mirrored hierarchy for the mirrorOf {@link SurfaceControl} + * + * Real Hierarchy Mirror + * SC (value that's returned) + * | + * A A' + * | | + * B B' + * + * @param mirrorOf The root of the hierarchy that should be mirrored. + * @return A SurfaceControl that's the parent of the root of the mirrored hierarchy. + * + * @hide + */ + public static SurfaceControl mirrorSurface(SurfaceControl mirrorOf) { + long nativeObj = nativeMirrorSurface(mirrorOf.mNativeObject); + SurfaceControl sc = new SurfaceControl(); + sc.assignNativeObject(nativeObj); + return sc; + } + /** * An atomic set of changes to a set of SurfaceControl. */ diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 06ff568202d5..a85830009f58 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -167,6 +167,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall boolean mUseAlpha = false; float mSurfaceAlpha = 1f; + boolean mClipSurfaceToBounds; @UnsupportedAppUsage boolean mHaveFrame = false; @@ -555,9 +556,52 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall super.dispatchDraw(canvas); } + /** + * Control whether the surface is clipped to the same bounds as the View. If true, then + * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop. + * + * @param enabled whether to enable surface clipping + * @hide + */ + public void setEnableSurfaceClipping(boolean enabled) { + mClipSurfaceToBounds = enabled; + invalidate(); + } + + @Override + public void setClipBounds(Rect clipBounds) { + super.setClipBounds(clipBounds); + + if (!mClipSurfaceToBounds) { + return; + } + + // When cornerRadius is non-zero, a draw() is required to update + // the viewport (rounding the corners of the clipBounds). + if (mCornerRadius > 0f && !isAboveParent()) { + invalidate(); + } + + if (mSurfaceControl != null) { + if (mClipBounds != null) { + mTmpRect.set(mClipBounds); + } else { + mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight); + } + SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this); + applier.scheduleApply( + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl) + .withWindowCrop(mTmpRect) + .build()); + } + } + private void clearSurfaceViewPort(Canvas canvas) { if (mCornerRadius > 0f) { canvas.getClipBounds(mTmpRect); + if (mClipSurfaceToBounds && mClipBounds != null) { + mTmpRect.intersect(mClipBounds); + } canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom, mCornerRadius, mCornerRadius, mRoundedViewportPaint); } else { @@ -583,6 +627,16 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } /** + * Returns the corner radius for the SurfaceView. + + * @return the radius of the corners in pixels + * @hide + */ + public float getCornerRadius() { + return mCornerRadius; + } + + /** * Control whether the surface view's surface is placed on top of another * regular surface view in the window (but still behind the window itself). * This is typically used to place overlays on top of an underlying media @@ -840,7 +894,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // crop the buffer to the surface size since the buffer producer may // use SCALING_MODE_SCALE and submit a larger size than the surface // size. - mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight); + if (mClipSurfaceToBounds && mClipBounds != null) { + mSurfaceControl.setWindowCrop(mClipBounds); + } else { + mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight); + } } mSurfaceControl.setCornerRadius(mCornerRadius); if (sizeChanged && !creating) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3756a7de47c0..fedd6fbe56ed 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -91,6 +91,7 @@ import android.view.SurfaceControl.Transaction; import android.view.View.AttachInfo; import android.view.View.FocusDirection; import android.view.View.MeasureSpec; +import android.view.WindowInsets.Type.InsetType; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -4528,6 +4529,8 @@ public final class ViewRootImpl implements ViewParent, private static final int MSG_INSETS_CONTROL_CHANGED = 31; private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32; private static final int MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED = 33; + private static final int MSG_SHOW_INSETS = 34; + final class ViewRootHandler extends Handler { @Override @@ -4591,6 +4594,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED"; case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED: return "MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED"; + case MSG_SHOW_INSETS: + return "MSG_SHOW_INSETS"; } return super.getMessageName(message); } @@ -4705,6 +4710,10 @@ public final class ViewRootImpl implements ViewParent, mInsetsController.onStateChanged((InsetsState) args.arg1); break; } + case MSG_SHOW_INSETS: { + mInsetsController.show(msg.arg1, msg.arg2 == 1); + break; + } case MSG_WINDOW_MOVED: if (mAdded) { final int w = mWinFrame.width(); @@ -7484,6 +7493,10 @@ public final class ViewRootImpl implements ViewParent, mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget(); } + private void showInsets(@InsetType int types, boolean fromIme) { + mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0).sendToTarget(); + } + public void dispatchMoved(int newX, int newY) { if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); if (mTranslator != null) { @@ -8599,6 +8612,14 @@ public final class ViewRootImpl implements ViewParent, } @Override + public void showInsets(@InsetType int types, boolean fromIme) { + final ViewRootImpl viewAncestor = mViewAncestor.get(); + if (viewAncestor != null) { + viewAncestor.showInsets(types, fromIme); + } + } + + @Override public void moved(int newX, int newY) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index b0467d084db1..f4f7d0b33fd1 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -39,11 +39,19 @@ import java.util.HashMap; class WindowlessWindowManager implements IWindowSession { private final static String TAG = "WindowlessWindowManager"; + private class State { + SurfaceControl mSurfaceControl; + WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); + State(SurfaceControl sc, WindowManager.LayoutParams p) { + mSurfaceControl = sc; + mParams.copyFrom(p); + } + }; /** * Used to store SurfaceControl we've built for clients to * reconfigure them if relayout is called. */ - final HashMap<IBinder, SurfaceControl> mScForWindow = new HashMap<IBinder, SurfaceControl>(); + final HashMap<IBinder, State> mStateForWindow = new HashMap<IBinder, State>(); public interface ResizeCompleteCallback { public void finished(SurfaceControl.Transaction completion); @@ -89,7 +97,7 @@ class WindowlessWindowManager implements IWindowSession { .setName(attrs.getTitle().toString()); final SurfaceControl sc = b.build(); synchronized (this) { - mScForWindow.put(window.asBinder(), sc); + mStateForWindow.put(window.asBinder(), new State(sc, attrs)); } if ((attrs.inputFeatures & @@ -125,22 +133,28 @@ class WindowlessWindowManager implements IWindowSession { } @Override - public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, + public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState) { - SurfaceControl sc = null; + State state = null; synchronized (this) { - sc = mScForWindow.get(window.asBinder()); + state = mStateForWindow.get(window.asBinder()); } - if (sc == null) { + if (state == null) { throw new IllegalArgumentException( "Invalid window token (never added or removed already)"); } + SurfaceControl sc = state.mSurfaceControl; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + if (inAttrs != null) { + state.mParams.copyFrom(inAttrs); + } + WindowManager.LayoutParams attrs = state.mParams; + final Rect surfaceInsets = attrs.surfaceInsets; int width = surfaceInsets != null ? attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width; diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index fc23c54e834e..358fdc78c0a0 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.Nullable; import android.text.TextUtils; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.regex.Pattern; diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index e415b41459ab..4d8378a34599 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -43,11 +43,6 @@ interface IPlatformCompat /** * Reports that a compatibility change is affecting an app process now. * - * <p>Same as {@link #reportChange(long, ApplicationInfo)}, except it receives a package name - * instead of an {@link ApplicationInfo} - * object, and finds an app info object based on the package name. Returns {@code true} if - * there is no installed package by that name. - * * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)}, * you do not need to call this API directly. The change will be reported for you. * @@ -57,6 +52,17 @@ interface IPlatformCompat void reportChangeByPackageName(long changeId, in String packageName); /** + * Reports that a compatibility change is affecting an app process now. + * + * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)}, + * you do not need to call this API directly. The change will be reported for you. + * + * @param changeId The ID of the compatibility change taking effect. + * @param uid The UID of the app in question. + */ + void reportChangeByUid(long changeId, int uid); + + /** * Query if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * @@ -95,4 +101,28 @@ interface IPlatformCompat * @return {@code true} if the change is enabled for the current app. */ boolean isChangeEnabledByPackageName(long changeId, in String packageName); + + /** + * Query if a given compatibility change is enabled for an app process. This method should + * be called when implementing functionality on behalf of the affected app. + * + * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid + * instead of an {@link ApplicationInfo} object, and finds an app info object based on the + * uid (or objects if there's more than one package associated with the UID). + * Returns {@code true} if there are no installed packages for the required UID, or if the + * change is enabled for ALL of the installed packages associated with the provided UID. Please + * use a more specific API if you want a different behaviour for multi-package UIDs. + * + * <p>If this method returns {@code true}, the calling code should implement the compatibility + * change, resulting in differing behaviour compared to earlier releases. If this method + * returns {@code false}, the calling code should behave as it did in earlier releases. + * + * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is + * no need to call that method directly. + * + * @param changeId The ID of the compatibility change in question. + * @param uid The UID of the app in question. + * @return {@code true} if the change is enabled for the current app. + */ + boolean isChangeEnabledByUid(long changeId, int uid); }
\ No newline at end of file diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 9fff447c2478..103c79d22530 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -35,7 +35,7 @@ import com.android.server.NetworkManagementSocketTagger; import dalvik.system.RuntimeHooks; import dalvik.system.VMRuntime; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index b3ec5f56e75a..a14b09343a01 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -306,6 +306,12 @@ class ZygoteConnection { } private void handleBootCompleted() { + try { + mSocketOutStream.writeInt(0); + } catch (IOException ioe) { + throw new IllegalStateException("Error writing to command socket", ioe); + } + VMRuntime.bootCompleted(); } diff --git a/core/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java index 2230c3134301..31ea5b2bf07c 100644 --- a/core/java/com/android/internal/util/MimeIconUtils.java +++ b/core/java/com/android/internal/util/MimeIconUtils.java @@ -27,7 +27,7 @@ import android.util.ArrayMap; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.Locale; import java.util.Objects; diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java b/core/java/com/android/internal/util/function/DecConsumer.java index 93c9adaac12d..0abb785bea32 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java +++ b/core/java/com/android/internal/util/function/DecConsumer.java @@ -14,16 +14,15 @@ * limitations under the License. */ -package com.android.server.integrity.engine; +package com.android.internal.util.function; + +import java.util.function.Consumer; /** - * The engine used to evaluate rules against app installs. + * A 10-argument {@link Consumer} * - * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine - * to allow/block that install. + * @hide */ -public final class RuleEvaluation { - private static final String TAG = "RuleEvaluation"; - - // TODO: Add singleton injection. +public interface DecConsumer<A, B, C, D, E, F, G, H, I, J> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); } diff --git a/core/java/com/android/internal/util/function/DecFunction.java b/core/java/com/android/internal/util/function/DecFunction.java new file mode 100644 index 000000000000..59fc5e6e6562 --- /dev/null +++ b/core/java/com/android/internal/util/function/DecFunction.java @@ -0,0 +1,28 @@ +/* + * 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.internal.util.function; + +import java.util.function.Function; + +/** + * A 10-argument {@link Function} + * + * @hide + */ +public interface DecFunction<A, B, C, D, E, F, G, H, I, J, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); +} diff --git a/core/java/com/android/internal/util/function/DecPredicate.java b/core/java/com/android/internal/util/function/DecPredicate.java new file mode 100644 index 000000000000..975993dc05dc --- /dev/null +++ b/core/java/com/android/internal/util/function/DecPredicate.java @@ -0,0 +1,28 @@ +/* + * 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.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 10-argument {@link Predicate} + * + * @hide + */ +public interface DecPredicate<A, B, C, D, E, F, G, H, I, J> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); +} diff --git a/core/java/com/android/internal/util/function/UndecConsumer.java b/core/java/com/android/internal/util/function/UndecConsumer.java new file mode 100644 index 000000000000..1a1d4ca600af --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecConsumer.java @@ -0,0 +1,28 @@ +/* + * 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.internal.util.function; + +import java.util.function.Consumer; + +/** + * A 11-argument {@link Consumer} + * + * @hide + */ +public interface UndecConsumer<A, B, C, D, E, F, G, H, I, J, K> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} diff --git a/core/java/com/android/internal/util/function/UndecFunction.java b/core/java/com/android/internal/util/function/UndecFunction.java new file mode 100644 index 000000000000..5cd324c2a7e5 --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecFunction.java @@ -0,0 +1,28 @@ +/* + * 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.internal.util.function; + +import java.util.function.Function; + +/** + * A 11-argument {@link Function} + * + * @hide + */ +public interface UndecFunction<A, B, C, D, E, F, G, H, I, J, K, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} diff --git a/core/java/com/android/internal/util/function/UndecPredicate.java b/core/java/com/android/internal/util/function/UndecPredicate.java new file mode 100644 index 000000000000..c09193eb7a11 --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecPredicate.java @@ -0,0 +1,28 @@ +/* + * 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.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 11-argument {@link Predicate} + * + * @hide + */ +public interface UndecPredicate<A, B, C, D, E, F, G, H, I, J, K> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} 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 d74e715605bb..7a17253ffd35 100755 --- a/core/java/com/android/internal/util/function/pooled/OmniFunction.java +++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java @@ -18,6 +18,8 @@ package com.android.internal.util.function.pooled; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; @@ -32,6 +34,8 @@ import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecConsumer; +import com.android.internal.util.function.UndecFunction; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -43,62 +47,65 @@ import java.util.function.Function; * * @hide */ -abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements +abstract class OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> implements PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>, QuadFunction<A, B, C, D, R>, QuintFunction<A, B, C, D, E, R>, HexFunction<A, B, C, D, E, F, R>, HeptFunction<A, B, C, D, E, F, G, R>, OctFunction<A, B, C, D, E, F, G, H, R>, NonaFunction<A, B, C, D, E, F, G, H, I, R>, + DecFunction<A, B, C, D, E, F, G, H, I, J, R>, + UndecFunction<A, B, C, D, E, F, G, H, I, J, K, R>, PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>, QuintConsumer<A, B, C, D, E>, HexConsumer<A, B, C, D, E, F>, 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>, PooledPredicate<A>, BiPredicate<A, B>, - PooledSupplier<R>, PooledRunnable, ThrowingRunnable, ThrowingSupplier<R>, - PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { + 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, + 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); + 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); @Override public R apply(A o, B o2) { - return invoke(o, o2, null, null, null, null, null, null, null); + return invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public R apply(A o) { - return invoke(o, null, null, null, null, null, null, null, null); + return invoke(o, null, null, null, null, null, null, null, null, null, null); } - public abstract <V> OmniFunction<A, B, C, D, E, F, G, H, I, V> andThen( + public abstract <V> OmniFunction<A, B, C, D, E, F, G, H, I, J, K, V> andThen( Function<? super R, ? extends V> after); - public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> negate(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> negate(); @Override public void accept(A o, B o2) { - invoke(o, o2, null, null, null, null, null, null, null); + invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public void accept(A o) { - invoke(o, null, null, null, null, null, null, null, null); + invoke(o, null, null, null, null, null, null, null, null, null, null); } @Override public void run() { - invoke(null, null, null, null, null, null, null, null, null); + invoke(null, null, null, null, null, null, null, null, null, null, null); } @Override public R get() { - return invoke(null, null, null, null, null, null, null, null, null); + return invoke(null, null, null, 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); + return (Boolean) invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public boolean test(A o) { - return (Boolean) invoke(o, null, null, null, null, null, null, null, null); + return (Boolean) invoke(o, null, null, null, null, null, null, null, null, null, null); } @Override @@ -113,72 +120,92 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements @Override public R apply(A a, B b, C c) { - return invoke(a, b, c, null, null, null, null, null, null); + return invoke(a, b, c, null, null, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c) { - invoke(a, b, c, null, null, null, null, null, null); + invoke(a, b, c, null, null, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d) { - return invoke(a, b, c, d, null, null, null, null, null); + return invoke(a, b, c, d, null, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e) { - return invoke(a, b, c, d, e, null, null, null, null); + return invoke(a, b, c, d, e, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f) { - return invoke(a, b, c, d, e, f, null, null, null); + return invoke(a, b, c, d, e, f, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g) { - return invoke(a, b, c, d, e, f, g, null, null); + return invoke(a, b, c, d, e, f, g, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g, H h) { - return invoke(a, b, c, d, e, f, g, h, null); + return invoke(a, b, c, d, e, f, g, h, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i) { - return invoke(a, b, c, d, e, f, g, h, i); + return invoke(a, b, c, d, e, f, g, h, i, null, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { + return invoke(a, b, c, d, e, f, g, h, i, j, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { + return invoke(a, b, c, d, e, f, g, h, i, j, k); } @Override public void accept(A a, B b, C c, D d) { - invoke(a, b, c, d, null, null, null, null, null); + invoke(a, b, c, d, null, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e) { - invoke(a, b, c, d, e, null, null, null, null); + invoke(a, b, c, d, e, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f) { - invoke(a, b, c, d, e, f, null, null, null); + invoke(a, b, c, d, e, f, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g) { - invoke(a, b, c, d, e, f, g, null, null); + invoke(a, b, c, d, e, f, g, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g, H h) { - invoke(a, b, c, d, e, f, g, h, null); + invoke(a, b, c, d, e, f, g, h, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i) { - invoke(a, b, c, d, e, f, g, h, i); + invoke(a, b, c, d, e, f, g, h, i, null, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { + invoke(a, b, c, d, e, f, g, h, i, j, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { + invoke(a, b, c, d, e, f, g, h, i, j, k); } @Override @@ -192,5 +219,5 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements } @Override - public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> recycleOnUse(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> recycleOnUse(); } 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 c00932e7a8aa..b9bf9337c3d6 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -21,6 +21,8 @@ import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire import android.os.Message; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; @@ -35,6 +37,8 @@ import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecConsumer; +import com.android.internal.util.function.UndecFunction; import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType; import java.util.function.BiConsumer; @@ -181,7 +185,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -198,7 +202,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -215,7 +219,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -246,7 +250,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -266,7 +270,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -284,7 +288,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -302,7 +306,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -320,7 +324,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -338,7 +342,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -356,7 +360,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -374,7 +378,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -392,7 +396,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -410,7 +414,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -442,7 +446,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -463,7 +467,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -482,7 +486,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -501,7 +505,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -520,7 +524,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -539,7 +543,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -558,7 +562,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -577,7 +581,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -596,7 +600,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -629,7 +633,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -651,7 +655,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -671,7 +675,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -691,7 +695,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -711,7 +715,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -731,7 +735,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -751,7 +755,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -771,7 +775,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -791,7 +795,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -811,7 +815,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -831,7 +835,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -865,7 +869,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -888,7 +892,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); } /** @@ -909,7 +913,7 @@ public interface PooledLambda { function, A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); } /** @@ -945,7 +949,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -969,7 +973,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); } /** @@ -991,7 +995,7 @@ public interface PooledLambda { ? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); } /** @@ -1028,7 +1032,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1053,7 +1057,7 @@ public interface PooledLambda { ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); } /** @@ -1077,7 +1081,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); } /** @@ -1115,7 +1119,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1142,7 +1146,7 @@ public interface PooledLambda { H arg8) { return acquire(PooledLambdaImpl.sPool, function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); } /** @@ -1167,7 +1171,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) { return acquire(PooledLambdaImpl.sPool, function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); } /** @@ -1207,7 +1211,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1235,7 +1239,7 @@ public interface PooledLambda { E arg5, F arg6, G arg7, H arg8, I arg9) { return acquire(PooledLambdaImpl.sPool, function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); } /** @@ -1261,7 +1265,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) { return acquire(PooledLambdaImpl.sPool, function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); } /** @@ -1302,7 +1306,209 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) } + */ + static <A, B, C, D, E, F, G, H, I, J> PooledRunnable obtainRunnable( + DecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J> function, A arg1, B arg2, C arg3, + D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + return acquire(PooledLambdaImpl.sPool, + function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) } + */ + static <A, B, C, D, E, F, G, H, I, J, R> PooledSupplier<R> obtainSupplier( + DecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + return acquire(PooledLambdaImpl.sPool, + function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8, arg9, arg10) } when handled + */ + static <A, B, C, D, E, F, G, H, I, J> Message obtainMessage( + DecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J> function, A arg1, B arg2, C arg3, + D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8, arg9, arg10, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, + * arg11) } + */ + static <A, B, C, D, E, F, G, H, I, J, K> PooledRunnable obtainRunnable( + UndecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K> function, A arg1, B arg2, + C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) { + return acquire(PooledLambdaImpl.sPool, + function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, arg11); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, + * arg11) } + */ + static <A, B, C, D, E, F, G, H, I, J, K, R> PooledSupplier<R> obtainSupplier( + UndecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, + K arg11) { + return acquire(PooledLambdaImpl.sPool, + function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, arg11); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @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 + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8, arg9, arg10, arg11) } when handled + */ + static <A, B, C, D, E, F, G, H, I, J, K> Message obtainMessage( + UndecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K> function, A arg1, B arg2, + C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8, arg9, arg10, arg11); return Message.obtain().setCallback(callback.recycleOnUse()); } } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java index e12c031f0036..c7502ef04f1b 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -26,6 +26,9 @@ import android.util.Pools; import com.android.internal.util.ArrayUtils; import com.android.internal.util.BitUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; +import com.android.internal.util.function.DecPredicate; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HeptPredicate; @@ -47,6 +50,9 @@ 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.UndecPredicate; import java.util.Arrays; import java.util.Objects; @@ -63,12 +69,12 @@ import java.util.function.Supplier; * @hide */ final class PooledLambdaImpl<R> extends OmniFunction<Object, - Object, Object, Object, Object, Object, Object, Object, Object, R> { + Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, R> { private static final boolean DEBUG = false; private static final String LOG_TAG = "PooledLambdaImpl"; - private static final int MAX_ARGS = 9; + private static final int MAX_ARGS = 11; private static final int MAX_POOL_SIZE = 50; @@ -134,7 +140,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, /** * Bit schema: - * AAAAAAAAABCDEEEEEEFFFFFF + * AAAAAAAAAAABCDEEEEEEFFFFFF * * Where: * A - whether {@link #mArgs arg} at corresponding index was specified at @@ -171,18 +177,18 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) { + Object a8, Object a9, Object a10, Object a11) { checkNotRecycled(); if (DEBUG) { Log.i(LOG_TAG, this + ".invoke(" + commaSeparateFirstN( - new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9 }, + new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 }, LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS))) + ")"); } final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4) && fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8) - && fillInArg(a9); + && fillInArg(a9) && fillInArg(a10) && fillInArg(a11); int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)); if (argCount != LambdaType.MASK_ARG_COUNT) { for (int i = 0; i < argCount; i++) { @@ -410,6 +416,48 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, } } } break; + + case 10: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((DecConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((DecPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7), popArg(8), popArg(9)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((DecFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9)); + } + } + } break; + + case 11: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((UndecConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((UndecPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((UndecFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + } + } + } break; } throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType)); } @@ -475,7 +523,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, */ static <E extends PooledLambda> E acquire(Pool pool, Object func, int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, - Object d, Object e, Object f, Object g, Object h, Object i) { + Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k) { PooledLambdaImpl r = acquire(pool); if (DEBUG) { Log.i(LOG_TAG, @@ -493,6 +541,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, + ", g = " + g + ", h = " + h + ", i = " + i + + ", j = " + j + + ", k = " + k + ")"); } r.mFunc = Preconditions.checkNotNull(func); @@ -508,6 +558,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, setIfInBounds(r.mArgs, 6, g); setIfInBounds(r.mArgs, 7, h); setIfInBounds(r.mArgs, 8, i); + setIfInBounds(r.mArgs, 9, j); + setIfInBounds(r.mArgs, 10, k); return (E) r; } @@ -564,13 +616,13 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - R> negate() { + Object, Object, R> negate() { throw new UnsupportedOperationException(); } @Override public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - V> andThen(Function<? super R, ? extends V> after) { + Object, Object, V> andThen(Function<? super R, ? extends V> after) { throw new UnsupportedOperationException(); } @@ -591,7 +643,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - R> recycleOnUse() { + Object, Object, R> recycleOnUse() { if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()"); mFlags |= FLAG_RECYCLE_ON_USE; return this; @@ -683,6 +735,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, case 7: return "Hept"; case 8: return "Oct"; case 9: return "Nona"; + case 10: return "Dec"; + case 11: return "Undec"; default: return "" + argCount + "arg"; } } diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index cc468f41a7f3..0e078dd3732d 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -30,6 +30,7 @@ import android.view.IWindowSession; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.PointerIcon; +import android.view.WindowInsets.Type.InsetType; import com.android.internal.os.IResultReceiver; @@ -75,6 +76,10 @@ public class BaseIWindow extends IWindow.Stub { } @Override + public void showInsets(@InsetType int types, boolean fromIme) throws RemoteException { + } + + @Override public void moved(int newX, int newY) { } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index f2a4f4fd203c..9445319e47ec 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -85,7 +85,8 @@ enum { // Dalvik other extra sections. HEAP_DALVIK_OTHER_LINEARALLOC, HEAP_DALVIK_OTHER_ACCOUNTING, - HEAP_DALVIK_OTHER_CODE_CACHE, + HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE, + HEAP_DALVIK_OTHER_APP_CODE_CACHE, HEAP_DALVIK_OTHER_COMPILER_METADATA, HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE, @@ -282,9 +283,10 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) is_swappable = true; } else if (base::EndsWith(name, ".vdex")) { which_heap = HEAP_DEX; - // Handle system@framework@boot and system/framework/boot + // Handle system@framework@boot and system/framework/boot|apex if ((strstr(name.c_str(), "@boot") != nullptr) || - (strstr(name.c_str(), "/boot"))) { + (strstr(name.c_str(), "/boot") != nullptr) || + (strstr(name.c_str(), "/apex") != nullptr)) { sub_heap = HEAP_DEX_BOOT_VDEX; } else { sub_heap = HEAP_DEX_APP_VDEX; @@ -295,9 +297,10 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) is_swappable = true; } else if (base::EndsWith(name, ".art") || base::EndsWith(name, ".art]")) { which_heap = HEAP_ART; - // Handle system@framework@boot* and system/framework/boot* + // Handle system@framework@boot* and system/framework/boot|apex* if ((strstr(name.c_str(), "@boot") != nullptr) || - (strstr(name.c_str(), "/boot"))) { + (strstr(name.c_str(), "/boot") != nullptr) || + (strstr(name.c_str(), "/apex") != nullptr)) { sub_heap = HEAP_ART_BOOT; } else { sub_heap = HEAP_ART_APP; @@ -309,9 +312,18 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) which_heap = HEAP_GL_DEV; } else if (base::StartsWith(name, "/dev/ashmem/CursorWindow")) { which_heap = HEAP_CURSOR; + } else if (base::StartsWith(name, "/dev/ashmem/jit-zygote-cache")) { + which_heap = HEAP_DALVIK_OTHER; + sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE; } else if (base::StartsWith(name, "/dev/ashmem")) { which_heap = HEAP_ASHMEM; } + } else if (base::StartsWith(name, "/memfd:jit-cache")) { + which_heap = HEAP_DALVIK_OTHER; + sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE; + } else if (base::StartsWith(name, "/memfd:jit-zygote-cache")) { + which_heap = HEAP_DALVIK_OTHER; + sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE; } else if (base::StartsWith(name, "[anon:")) { which_heap = HEAP_UNKNOWN; if (base::StartsWith(name, "[anon:dalvik-")) { @@ -339,7 +351,7 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) sub_heap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE; } else if (base::StartsWith(name, "[anon:dalvik-jit-code-cache") || base::StartsWith(name, "[anon:dalvik-data-code-cache")) { - sub_heap = HEAP_DALVIK_OTHER_CODE_CACHE; + sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE; } else if (base::StartsWith(name, "[anon:dalvik-CompilerMetadata")) { sub_heap = HEAP_DALVIK_OTHER_COMPILER_METADATA; } else { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 1ca9383b920f..d5cd278063c0 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1244,6 +1244,15 @@ static jlong nativeReadTransactionFromParcel(JNIEnv* env, jclass clazz, jobject return reinterpret_cast<jlong>(transaction.release()); } +static jlong nativeMirrorSurface(JNIEnv* env, jclass clazz, jlong mirrorOfObj) { + sp<SurfaceComposerClient> client = SurfaceComposerClient::getDefault(); + SurfaceControl *mirrorOf = reinterpret_cast<SurfaceControl*>(mirrorOfObj); + sp<SurfaceControl> surface = client->mirrorSurface(mirrorOf); + + surface->incStrong((void *)nativeCreate); + return reinterpret_cast<jlong>(surface.get()); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -1394,6 +1403,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeReadTransactionFromParcel }, {"nativeWriteTransactionToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteTransactionToParcel }, + {"nativeMirrorSurface", "(J)J", + (void*)nativeMirrorSurface }, }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/core/proto/android/telecomm/enums.proto b/core/proto/android/telecomm/enums.proto index 7a2ba624c021..5ca4a85f7c6a 100644 --- a/core/proto/android/telecomm/enums.proto +++ b/core/proto/android/telecomm/enums.proto @@ -110,6 +110,24 @@ enum CallStateEnum { * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}. */ PULLING = 10; + + /** + * Indicates that an incoming call has been answered by the in-call UI, but Telephony hasn't yet + * set the call to active. + */ + ANSWERED = 11; + + /** + * Indicates that the call is undergoing audio processing by a different app in the background. + * @see android.telecom.Call#STATE_AUDIO_PROCESSING + */ + AUDIO_PROCESSING = 12; + + /** + * Indicates that the call is in a fake ringing state. + * @see android.telecom.Call#STATE_SIMULATED_RINGING + */ + SIMULATED_RINGING = 13; } // Disconnect causes for a call. Primarily used by android/telecom/DisconnectCause.java diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index d3bf0dd7a7e8..e9d5bb135e02 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -20,7 +20,6 @@ android_test { "android.test.base", ], static_libs: ["androidx.test.rules", "truth-prebuilt"], - test_suites: ["general-tests"], sdk_version: "test_current", platform_apis: true, } diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java index 6ec3dc923efd..0ac00b8e9bbc 100644 --- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java +++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java @@ -173,7 +173,7 @@ public class UsageStatsTest { left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1); assertEquals(left.mLastTimeUsed, 350000); assertEquals(left.mLastTimeVisible, 400000); - assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertTrue(left.mActivities.indexOfKey(1) < 0); assertEquals(left.mTotalTimeInForeground, 350000 - 200000); assertEquals(left.mTotalTimeVisible, 400000 - 200000); @@ -231,7 +231,7 @@ public class UsageStatsTest { left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1); assertEquals(left.mLastTimeUsed, 300000); assertEquals(left.mLastTimeVisible, 400000); - assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertTrue(left.mActivities.indexOfKey(1) < 0); assertEquals(left.mTotalTimeInForeground, 300000 - 200000); assertEquals(left.mTotalTimeVisible, 400000 - 100000); } @@ -249,7 +249,7 @@ public class UsageStatsTest { left.update("com.test.activity1", 200000, ACTIVITY_STOPPED, 1); assertEquals(left.mLastTimeUsed, 200000); assertEquals(left.mLastTimeVisible, 200000); - assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertTrue(left.mActivities.indexOfKey(1) < 0); assertEquals(left.mTotalTimeInForeground, 200000 - 100000); assertEquals(left.mTotalTimeVisible, 200000 - 100000); @@ -359,14 +359,14 @@ public class UsageStatsTest { left.update("com.test.activity1", 550000, ACTIVITY_STOPPED, 1); assertEquals(left.mLastTimeUsed, 450000); assertEquals(left.mLastTimeVisible, 550000); - assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED); + assertTrue(left.mActivities.indexOfKey(1) < 0); assertEquals(left.mTotalTimeInForeground, 350000); assertEquals(left.mTotalTimeVisible, 350000 + 100000 /*550000 - 450000*/); left.update("com.test.activity2", 650000, ACTIVITY_STOPPED, 2); assertEquals(left.mLastTimeUsed, 450000); assertEquals(left.mLastTimeVisible, 650000); - assertEquals(left.mActivities.get(2), ACTIVITY_STOPPED); + assertTrue(left.mActivities.indexOfKey(2) < 0); assertEquals(left.mTotalTimeInForeground, 350000); assertEquals(left.mTotalTimeVisible, 450000 + 100000 /*650000 - 550000*/); } diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml index 054f68ba9e5c..f1ba3f6f7859 100644 --- a/data/etc/hiddenapi-package-whitelist.xml +++ b/data/etc/hiddenapi-package-whitelist.xml @@ -53,6 +53,10 @@ Do NOT include any apps that are updatable via Play Store! <hidden-api-whitelisted-app package="com.android.providers.media" /> <hidden-api-whitelisted-app package="com.android.providers.tv" /> <hidden-api-whitelisted-app package="com.android.providers.userdictionary" /> + <!-- TODO (b/141954427): Remove networkstack --> + <hidden-api-whitelisted-app package="com.android.networkstack" /> + <!-- TODO (b/141954427): Remove wifistack --> + <hidden-api-whitelisted-app package="com.android.server.wifistack" /> <hidden-api-whitelisted-app package="com.android.smspush" /> <hidden-api-whitelisted-app package="com.android.spare_parts" /> <hidden-api-whitelisted-app package="com.android.statementservice" /> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 2dfb777592fd..a2402e25c556 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1,16 +1,2170 @@ { "version": "1.0.0", "messages": { + "-2146181682": { + "message": "Releasing screen wakelock, obscured by %s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-2138637148": { + "message": "Clearing focused app, displayId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/ActivityDisplay.java" + }, + "-2109864870": { + "message": "app-release(): mOuter=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-2086729999": { + "message": "Removing app token: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-2072089308": { + "message": "Attempted to add window with token that is a sub-window: %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-2039580386": { + "message": "Attempted to add input method window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-2024464438": { + "message": "app-onAnimationFinished(): mOuter=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-2012562539": { + "message": "startAnimation(): Notify animation start:", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-2002500255": { + "message": "Defer removing snapshot surface in %dms", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" + }, + "-1991255017": { + "message": "Drawing snapshot surface sizeMismatch=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" + }, + "-1976930686": { + "message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1963461591": { + "message": "Removing %s from %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1958209312": { + "message": "Clear freezing of %s: hidden=%b freezing=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-1953668890": { + "message": "Can't start recents animation, nextAppTransition=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "-1949279037": { + "message": "Attempted to add input method window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1939358269": { + "message": "mRecentScreenshotAnimator finish", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-1938839202": { + "message": "SURFACE LEAK DESTROY: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-1915280162": { + "message": "Attempted to add wallpaper window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1886298021": { + "message": "setAppStartingWindow: token=%s pkg=%s transferFrom=%s newTask=%b taskSwitch=%b processRunning=%b allowTaskSnapshot=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-1884933373": { + "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1872288685": { + "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "-1868124841": { + "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-1862269827": { + "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "-1838803135": { + "message": "Attempted to set windowing mode to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1836092044": { + "message": "Creating SnapshotStartingData", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1824578273": { + "message": "Reporting new frame to %s: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1822611824": { + "message": "\tRemove token=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-1797409732": { + "message": "Skipping %s because %s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-1770075711": { + "message": "Adding window client %s that is dead, aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1768557332": { + "message": "removeWallpaperAnimation()", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-1750206390": { + "message": "Exception thrown when creating surface for client %s (%s). %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1747461042": { + "message": "set mOrientationChanging of %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1741065110": { + "message": "No app is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-1736245181": { + "message": "Tried to remove starting window but startingWindow was null: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1730156332": { + "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-1710206702": { + "message": "Display id=%d is frozen while keyguard locked, return %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-1661704580": { + "message": "Attempted to set replacing window on non-existing app token %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1661404819": { + "message": "applyAnimation: atoken=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1632122349": { + "message": "Changing surface while display frozen: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1597650595": { + "message": "removeAppToken: %s delayed=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1596995693": { + "message": "startAnimation", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-1587841219": { + "message": "Focus moving from %s to %s displayId=%d", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1568331821": { + "message": "Enabling listeners", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-1561845439": { + "message": "reParentWindowToken: removing window token=%s from task=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1545962566": { + "message": "View server did not start", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1526645239": { + "message": "Timeout waiting for drawn: undrawn=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1524305318": { + "message": "Nulling last startingData", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1519226370": { + "message": "startingData was nulled out before handling mAddStartingWindow: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1515151503": { + "message": ">>> OPEN TRANSACTION removeReplacedWindows", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "-1497837552": { + "message": "onAnimationFinished(): mPendingAnimations=%d", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-1483752006": { + "message": " THUMBNAIL %s: CREATE", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/AppWindowThumbnail.java" + }, + "-1470632028": { + "message": "Marking app token %s with replacing windows.", + "level": "DEBUG", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1455600136": { + "message": "Attempted to add Dream window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1448427933": { + "message": "startingWindow was set but startingSurface==null, couldn't remove", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1443029505": { + "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1434147454": { + "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-1427184084": { + "message": "addWindow: New client %s: window=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1413901262": { + "message": "startRecentsActivity(): intent=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "-1391944764": { + "message": "SURFACE DESTROY: %s. %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-1389772804": { + "message": "Attempted to add voice interaction window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1350198040": { + "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1318134223": { + "message": "No longer Stopped: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1270731689": { + "message": "Attempted to set replacing window on app token with no content %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1270148832": { + "message": "Resize start waiting for draw, mDrawState=DRAW_PENDING in %s, surfaceController %s", + "level": "VERBOSE", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1263554915": { + "message": "Attempted to add Dream window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1259022216": { + "message": "SURFACE HIDE ( %s ): %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-1257821162": { + "message": "OUT SURFACE %s: copied", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1219773477": { + "message": "setInputConsumerEnabled(%s): mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-1207757583": { + "message": "startAnimation(): Notify animation start: %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-1176488860": { + "message": "SURFACE isSecure=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-1156118957": { + "message": "Updated config=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "-1144293044": { + "message": "SURFACE SET FREEZE LAYER: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-1130891072": { + "message": "Orientation continue waiting for draw in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-1130868271": { + "message": "Resizing %s WITH DRAW PENDING", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1117599386": { + "message": "Deferring rotation, display is not enabled.", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-1113134997": { + "message": "Attempted to add application window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1103716954": { + "message": "Not removing %s due to exit animation", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1103115659": { + "message": "Performing post-rotate rotation", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "-1099052739": { + "message": "\tAdd token=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-1097148233": { + "message": "commitVisibility: %s: hidden=%b hiddenRequested=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1089874824": { + "message": "SURFACE SHOW (performLayout): %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-1077196445": { + "message": "Add starting %s: startingData=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-1076978367": { + "message": "thawRotation: mRotation=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1060365734": { + "message": "Attempted to add QS dialog window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1047945589": { + "message": "Remove client=%x, surfaceController=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1044506655": { + "message": "New transit away from wallpaper: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-1042574499": { + "message": "Attempted to add Accessibility overlay window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-1009117329": { + "message": "isFetchingAppTransitionSpecs=true", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-1001633850": { + "message": "Removing focused app token:%s displayId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-993378225": { + "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_DRAW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-986746907": { + "message": "Starting window removed %s", + "level": "DEBUG", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-979259577": { + "message": "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-955458843": { + "message": "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-953872371": { + "message": "setClientHidden: %s clientHidden=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-928291778": { + "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "-916108501": { + "message": "Adding %s to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-914253865": { + "message": "Attempted to add voice interaction window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-883738232": { + "message": "Adding more than one toast window for UID at a time.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-874446906": { + "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-861859917": { + "message": "Attempted to add window to a display that does not exist: %d. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-861707633": { + "message": "Destroying surface %s called by %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-856025122": { + "message": "SURFACE transparentRegionHint=%s: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-853404763": { + "message": "\twallpaper=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-853226675": { + "message": "Attempted to add window with exiting application token .%s Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-809771899": { + "message": "findFocusedWindow: Reached focused app=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-807062773": { + "message": "Aborted starting %s: removed=%b startingData=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-793346159": { + "message": "New transit into wallpaper: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-784959154": { + "message": "Attempted to add private presentation window to a non-private display. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-783405930": { + "message": "Performing post-rotate rotation", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-771282525": { + "message": "Losing focus: %s", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-760801764": { + "message": "onAnimationCancelled", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + }, + "-754503024": { + "message": "Relayout %s: oldVis=%d newVis=%d. %s", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-747671114": { + "message": "Failed looking up window callers=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-714291355": { + "message": "Losing delayed focus: %s", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-694710814": { + "message": "Pausing rotation during drag", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DragState.java" + }, + "-687185281": { + "message": "New topFocusedDisplayId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "-666510420": { + "message": "With display frozen, orientationChangeComplete=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "-666419717": { + "message": "Creating animation bounds layer", + "level": "INFO", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-653156702": { + "message": "createAppAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-650040763": { + "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-635082269": { + "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-622997754": { + "message": "postWindowRemoveCleanupLocked: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-618015844": { + "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b mOnlyCore=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-583031528": { + "message": "%s", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-576070986": { + "message": "Performing post-rotate rotation after seamless rotation", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-573268667": { + "message": "applyAnimation: transition animation is disabled or skipped. atoken=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-554834595": { + "message": "Display id=%d is frozen, return %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-549028919": { + "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-545190927": { + "message": "<<< CLOSE TRANSACTION animate", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowAnimator.java" + }, + "-519504830": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "-507657818": { + "message": "Window %s is already added", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-496681057": { + "message": "Attempted to get remove mode of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-481924678": { + "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "-477481651": { + "message": "SURFACE DESTROY PENDING: %s. %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-445944810": { + "message": "finish(%b): mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-444624452": { + "message": "REPARENT from: %s to: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-439951996": { + "message": "Disabling listeners", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-415865166": { + "message": "findFocusedWindow: Found new focus @ %s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-405536909": { + "message": "Removing snapshot surface", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" + }, + "-393505149": { + "message": "unable to update pointer icon", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-386552155": { + "message": "Attempted to set system decors flag to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-379068494": { + "message": "unknownApps is not empty: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-371630969": { + "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-367797467": { + "message": "Creating SplashScreenStartingData", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-344488673": { + "message": "Finishing drawing window %s: mDrawState=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-336658140": { + "message": "Checking theme of starting window: 0x%x", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-324085783": { + "message": "SURFACE CROP %s: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-322035974": { + "message": "App freeze timeout expired.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-320419645": { + "message": "Removing replaced window: %s", + "level": "DEBUG", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-198463978": { + "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-193782861": { + "message": "Final remove of window: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_MOVEMENT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-167822951": { + "message": "Attempted to add starting window to token with already existing starting window", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-129722369": { + "message": "New transit: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "-121104356": { + "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-117925665": { + "message": "addAppToken: %s task=%s at %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-116086365": { + "message": "******************** ENABLING SCREEN!", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-106400104": { + "message": "Preload recents with %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "-104758113": { + "message": "Removing app %s delayed=%b animation=%s animating=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-96848838": { + "message": "Gaining focus: %s", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-87705714": { + "message": "findFocusedWindow: focusedApp=null using new focus @ %s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-87703044": { + "message": "Boot completed: SurfaceFlinger is dead!", + "level": "ERROR", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "-86763148": { + "message": " KILL SURFACE SESSION %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/Session.java" + }, + "-34965929": { + "message": "Moving pending starting from %s to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "-29233992": { + "message": "SURFACE CLEAR CROP: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-7343917": { + "message": "onAnimationFinished(): targetStack=%s targetActivity=%s mRestoreTargetBehindStack=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "9803449": { + "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "10608884": { + "message": " FREEZE %s: CREATE", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, + "11060725": { + "message": "Attempted to get system decors flag of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "17696244": { + "message": "startAnimation(): mPendingStart=%b mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "38267433": { + "message": "Attempted to reset replacing window on non-existing app token %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "44171776": { + "message": "Resetting app token %s of replacing window marks.", + "level": "DEBUG", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "51200510": { + "message": " BLACK %s: DESTROY", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/BlackFrame.java" + }, + "51628177": { + "message": "Attempted to get windowing mode of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "83950285": { + "message": "removeAnimation(%d)", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "91350919": { + "message": "Attempted to set IME flag to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "95281111": { + "message": "Attempted to get IME flag of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "95902367": { + "message": "Relayout of %s: focusMayChange=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "100936473": { + "message": "Wallpaper animation!", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "115108840": { + "message": "Removing startingView=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "118187173": { + "message": "Enqueueing ADD_STARTING", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "123161180": { + "message": "SEVER CHILDREN", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "150351993": { + "message": "addWindow: %s startingWindow=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "152914409": { + "message": " BLACK %s: CREATE layer=%d", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/BlackFrame.java" + }, + "154699456": { + "message": "Last window, removing starting window %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "173419252": { + "message": "No thumbnail header bitmap for: %d", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "184362060": { + "message": "screenshotTask(%d): mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "186668272": { + "message": "Now changing app %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "194124419": { + "message": "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "196230599": { + "message": "Moving existing starting %s from %s to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "221540118": { + "message": "mUserActivityTimeout set to %d", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "241961619": { + "message": "Adding %s to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "246676969": { + "message": "Attempted to add window with non-application token .%s Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "248210157": { + "message": "Finishing remote animation", + "level": "INFO", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "254883724": { + "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "255692476": { + "message": "**** GOOD TO GO", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "269576220": { + "message": "Resuming rotation after drag", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DragState.java" + }, + "274773837": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "285317231": { + "message": "Input focus has changed to %s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" + }, + "288485303": { + "message": "Attempted to set remove mode to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "289967521": { + "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "292904800": { + "message": "Deferring rotation, animation in progress.", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "302992539": { + "message": "addAnimation(%s)", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "309039362": { + "message": "SURFACE MATRIX [%f,%f,%f,%f]: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "342460966": { + "message": "DRAG %s: pos=(%d,%d)", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/DragState.java" + }, + "344795667": { + "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "355720268": { + "message": "stopFreezingDisplayLocked: Unfreezing now", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "371641947": { + "message": "Window Manager Crash %s", + "level": "WTF", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "374972436": { + "message": "performEnableScreen: Waiting for anim complete", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "385096046": { + "message": "Delaying loss of focus...", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "399841913": { + "message": "SURFACE RECOVER DESTROY: %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "416664944": { + "message": "No longer freezing: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "417311568": { + "message": "onResize: Resizing %s", + "level": "DEBUG", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "424524729": { + "message": "Attempted to add wallpaper window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "435494046": { + "message": "Attempted to add window to a display for which the application does not have access: %d. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "457951957": { + "message": "\tNot visible=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + }, + "463993897": { + "message": "Aborted waiting for drawn: %s", + "level": "WARN", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "474000473": { + "message": "No stack above target stack=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "481370485": { + "message": "Computed rotation=%d for display id=%d based on lastOrientation=%d and oldRotation=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "490877640": { + "message": "onStackOrderChanged(): stack=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "492980365": { + "message": "TRANSIT_TASK_OPEN_BEHIND, adding %s to mOpeningApps", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "495032901": { + "message": "Expected target stack=%s to restored behind stack=%s but it is behind stack=%s", + "level": "WARN", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "508887531": { + "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "557227556": { + "message": "onAnimationFinished(): Notify animation finished:", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "558823034": { + "message": "SURFACE isOpaque=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "585096182": { + "message": "SURFACE isColorSpaceAgnostic=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "594260577": { + "message": "createWallpaperAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "600140673": { + "message": "checkBootAnimationComplete: Waiting for anim complete", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "608694300": { + "message": " NEW SURFACE SESSION %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/Session.java" + }, + "620368427": { + "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "628276090": { + "message": "Delaying app transition for screen rotation animation to finish", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "631792420": { + "message": "Attempted to add window with token that is not a window: %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "633654009": { + "message": "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "644675193": { + "message": "Real start recents", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "646155519": { + "message": "Started intent=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "662572728": { + "message": "Attempted to add a toast window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "665256544": { + "message": "All windows drawn!", + "level": "DEBUG", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "668425960": { + "message": "Notify removed startingWindow %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, "676824470": { "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.", "level": "ERROR", "group": "TEST_GROUP", "at": "com\/android\/server\/wm\/ProtoLogGroup.java" + }, + "685047360": { + "message": "Resizing window %s", + "level": "VERBOSE", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "690411811": { + "message": "goodToGo(): No apps to animate", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "693423992": { + "message": "setAnimationLocked: setting mFocusMayChange true", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "704998117": { + "message": "Failed to create surface control for %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "745391677": { + "message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "758852025": { + "message": "Surface returned was null: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "765395228": { + "message": "onAnimationFinished(): controller=%s reorderMode=%d", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "791468751": { + "message": "Pausing rotation during re-position", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/TaskPositioner.java" + }, + "794570322": { + "message": "Now closing app %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "811802785": { + "message": "Changing app %s hidden=%b performLayout=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "829434921": { + "message": "Draw state now committed in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "835814848": { + "message": "%s", + "level": "INFO", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "845234215": { + "message": "App is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "847534382": { + "message": "Non-null appWindowToken for system window of rootType=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "853091290": { + "message": "Moved stack=%s behind stack=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "868946719": { + "message": "notifyAppResumed: wasStopped=%b %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "873914452": { + "message": "goodToGo()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "884043983": { + "message": "removeDeadWindows: %s", + "level": "WARN", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "892244061": { + "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "898863925": { + "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "913494177": { + "message": "removeAllWindowsIfPossible: removing win=%s", + "level": "WARN", + "group": "WM_DEBUG_WINDOW_MOVEMENT", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "916191774": { + "message": "Orientation change complete in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "917739349": { + "message": "Set focused app to: %s moveFocusNow=%b displayId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/ActivityDisplay.java" + }, + "954470154": { + "message": "FORCED DISPLAY SCALING DISABLED", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "990058731": { + "message": "notifyAppStopped: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1001904964": { + "message": "***** BOOT TIMEOUT: forcing display enabled", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1004585481": { + "message": "%s forcing orientation to %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1021057640": { + "message": "Marking app token %s with replacing child windows.", + "level": "DEBUG", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1051545910": { + "message": "Exit animation finished in %s: remove=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1073230342": { + "message": "startAnimation", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + }, + "1089714158": { + "message": " FREEZE %s: DESTROY", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, + "1108406230": { + "message": "stopFreezingDisplayLocked: Returning mWaitingForConfig=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1112047265": { + "message": "finishDrawingWindow: %s mDrawState=%s", + "level": "DEBUG", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1115417974": { + "message": "FORCED DISPLAY SIZE: %dx%d", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1140424002": { + "message": "Finished screen turning on...", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "1160771501": { + "message": "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1166381079": { + "message": "Execute app transition: %s, displayId: %d Callers=%s", + "level": "WARN", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1195433019": { + "message": "Clearing startingData for token=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1208313423": { + "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1219600119": { + "message": "addWindow: win=%s Callers=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "1220075598": { + "message": "SURFACE SIZE %dx%d: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "1224307091": { + "message": "checkBootAnimationComplete: Animation complete!", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1244668962": { + "message": "Added starting %s: startingWindow=%s startingView=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1288731814": { + "message": "WindowState.hideLw: setting mFocusMayChange true", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1325649102": { + "message": "Bad requesting window %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1329340614": { + "message": "Orientation not waiting for draw in %s, surfaceController %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1331177619": { + "message": "Attempted to add a toast window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1358462645": { + "message": "Looking for focus: %s, flags=%d, canReceive=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1401700824": { + "message": "Window drawn win=%s", + "level": "DEBUG", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1404220922": { + "message": "Translucent=%s Floating=%s ShowWallpaper=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1422781269": { + "message": "Resuming rotation after re-position", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/TaskPositioner.java" + }, + "1423418408": { + "message": "unable to restore pointer icon", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1423592961": { + "message": "<<< CLOSE TRANSACTION removeReplacedWindows", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "1430336882": { + "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1434383382": { + "message": "Attempted to get flag of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1448683958": { + "message": "Override pending remote transitionSet=%b adapter=%s", + "level": "INFO", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "1457990604": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "1469292670": { + "message": "Changing focus from %s to %s displayId=%d Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1495525537": { + "message": "createWallpaperAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "1496418389": { + "message": "Removing starting %s from %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1497304204": { + "message": "Deferring rotation, rotation is paused.", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "1504168072": { + "message": "removeIfPossible: %s callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1518495446": { + "message": "removeWindowToken: Attempted to remove non-existing token: %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1519757176": { + "message": "setHomeApp(%s)", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "1521476038": { + "message": "Attempted to set flag to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1525976603": { + "message": "cancelAnimation(): reason=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "1531527061": { + "message": "createAnimationAdapter(): token=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "1563755163": { + "message": "Permission Denial: %s from pid=%d, uid=%d requires %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1573332272": { + "message": "Display id=%d selected orientation %d, got rotation %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "1577579529": { + "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b", + "level": "ERROR", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1589610525": { + "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "1628345525": { + "message": "Now opening app %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "1634557978": { + "message": "**** Dismissing screen rotation animation", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1635462459": { + "message": "onMovedByResize: Moving %s", + "level": "DEBUG", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1637745145": { + "message": "Clear freezing of %s force=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1720696061": { + "message": "Adding window to Display that has been removed.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1739298851": { + "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1747941491": { + "message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "1756082882": { + "message": "Orientation change skips hidden %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "1762317752": { + "message": "Expected target stack=%s to be top most but found stack=%s", + "level": "WARN", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "1764592478": { + "message": "reparent: moving app token=%s to task=%d at %d", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1774661765": { + "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1814552834": { + "message": "performLayout: App token exiting now removed %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1836306327": { + "message": "Skipping set freeze of %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "1865125884": { + "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b", + "level": "DEBUG", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "1865246212": { + "message": "\tapp=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "1866772666": { + "message": "SAFE MODE not enabled", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "1878395049": { + "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1883987026": { + "message": "removeAppToken make exiting: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "1891501279": { + "message": "cancelAnimation(): reason=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "1921821199": { + "message": "Preserving %s until the new one is added", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "1947239194": { + "message": "Deferring rotation, still finishing previous rotation", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "1964565370": { + "message": "Starting remote animation", + "level": "INFO", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "1984470582": { + "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/TaskScreenshotAnimatable.java" + }, + "1984738415": { + "message": "Now animating app in place %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "1984782949": { + "message": ">>> OPEN TRANSACTION animate", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowAnimator.java" + }, + "1993685727": { + "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "2016061474": { + "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "2018454757": { + "message": "WS.removeImmediately: %s Already removed...", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "2028163120": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" + }, + "2034780299": { + "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "2045641491": { + "message": "Checking %d opening apps (frozen=%b timeout=%b)...", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "2054958632": { + "message": "Schedule remove starting %s startingWindow=%s startingView=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "2057434754": { + "message": "\tvisible=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + }, + "2076259606": { + "message": "Finish starting %s: first real window is shown, no animation", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/AppWindowToken.java" + }, + "2083556954": { + "message": "Set mOrientationChanging of %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "2086878461": { + "message": "Could not send command %s with parameters %s. %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "2088592090": { + "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" + }, + "2096635066": { + "message": "Acquiring screen wakelock due to %s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "2114149926": { + "message": "Not removing %s because app died while it's visible", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "2128604122": { + "message": "findFocusedWindow: No focusable windows.", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "2128917433": { + "message": "onProposedRotationChanged, rotation=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "2137411379": { + "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" } }, "groups": { "TEST_GROUP": { "tag": "WindowManagetProtoLogTest" + }, + "WM_DEBUG_ADD_REMOVE": { + "tag": "WindowManager" + }, + "WM_DEBUG_APP_TRANSITIONS": { + "tag": "WindowManager" + }, + "WM_DEBUG_APP_TRANSITIONS_ANIM": { + "tag": "WindowManager" + }, + "WM_DEBUG_BOOT": { + "tag": "WindowManager" + }, + "WM_DEBUG_DRAW": { + "tag": "WindowManager" + }, + "WM_DEBUG_FOCUS": { + "tag": "WindowManager" + }, + "WM_DEBUG_FOCUS_LIGHT": { + "tag": "WindowManager" + }, + "WM_DEBUG_KEEP_SCREEN_ON": { + "tag": "WindowManager" + }, + "WM_DEBUG_ORIENTATION": { + "tag": "WindowManager" + }, + "WM_DEBUG_RECENTS_ANIMATIONS": { + "tag": "WindowManager" + }, + "WM_DEBUG_REMOTE_ANIMATIONS": { + "tag": "WindowManager" + }, + "WM_DEBUG_RESIZE": { + "tag": "WindowManager" + }, + "WM_DEBUG_SCREEN_ON": { + "tag": "WindowManager" + }, + "WM_DEBUG_STARTING_WINDOW": { + "tag": "WindowManager" + }, + "WM_DEBUG_WINDOW_MOVEMENT": { + "tag": "WindowManager" + }, + "WM_ERROR": { + "tag": "WindowManager" + }, + "WM_SHOW_SURFACE_ALLOC": { + "tag": "WindowManager" + }, + "WM_SHOW_TRANSACTIONS": { + "tag": "WindowManager" } } } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 6b47d1dff781..68480ced0692 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -27,7 +27,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -134,23 +133,27 @@ public class LocationManager { /** * This key is no longer in use. * - * Key used for a Bundle extra holding an Integer status value - * when a status change is broadcast using a PendingIntent. + * <p>Key used for a Bundle extra holding an Integer status value when a status change is + * broadcast using a PendingIntent. * - * @deprecated Status changes are deprecated and no longer broadcast. + * @deprecated Status changes are deprecated and no longer broadcast from Android Q onwards. */ @Deprecated public static final String KEY_STATUS_CHANGED = "status"; /** - * Key used for a Bundle extra holding an Boolean status value - * when a provider enabled/disabled event is broadcast using a PendingIntent. + * Key used for an extra holding a boolean enabled/disabled status value when a provider + * enabled/disabled event is broadcast using a PendingIntent. + * + * @see #requestLocationUpdates(String, long, long, PendingIntent) */ public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; /** - * Key used for a Bundle extra holding a Location value - * when a location change is broadcast using a PendingIntent. + * Key used for an extra holding a {@link Location} value when a location change is broadcast + * using a PendingIntent. + * + * @see #requestLocationUpdates(String, long, long, PendingIntent) */ public static final String KEY_LOCATION_CHANGED = "location"; @@ -382,7 +385,7 @@ public class LocationManager { } /** - * Returns the current enabled/disabled state of location. + * Returns the current enabled/disabled state of location for the given user. * * @param userHandle the user to query * @return true if location is enabled and false if location is disabled. @@ -399,7 +402,7 @@ public class LocationManager { } /** - * Enables or disables the location setting. + * Enables or disables location for the given user. * * @param enabled true to enable location and false to disable location. * @param userHandle the user to set @@ -455,7 +458,7 @@ public class LocationManager { @SystemApi public boolean isProviderEnabledForUser( @NonNull String provider, @NonNull UserHandle userHandle) { - checkProvider(provider); + Preconditions.checkArgument(provider != null, "invalid null provider"); try { return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier()); @@ -484,7 +487,7 @@ public class LocationManager { @RequiresPermission(WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser( @NonNull String provider, boolean enabled, @NonNull UserHandle userHandle) { - checkProvider(provider); + Preconditions.checkArgument(provider != null, "invalid null provider"); return Settings.Secure.putStringForUser( mContext.getContentResolver(), @@ -494,57 +497,45 @@ public class LocationManager { } /** - * Get the last known location. - * - * <p>This location could be very old so use - * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can - * also return null if no previous location is available. + * Gets the last known location from the fused provider, or null if there is no last known + * location. The returned location may be quite old in some circumstances, so the age of the + * location should always be checked. * - * <p>Always returns immediately. - * - * @return The last known location, or null if not available - * @throws SecurityException if no suitable permission is present + * @return the last known location, or null if not available + * @throws SecurityException if no suitable location permission is present * * @hide */ @Nullable + @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public Location getLastLocation() { - String packageName = mContext.getPackageName(); - try { - return mService.getLastLocation(null, packageName); + return mService.getLastLocation(null, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Returns a Location indicating the data from the last known - * location fix obtained from the given provider. - * - * <p> This can be done - * without starting the provider. Note that this location could - * be out-of-date, for example if the device was turned off and - * moved to another location. - * - * <p> If the provider is currently disabled, null is returned. + * Gets the last known location from the given provider, or null if there is no last known + * location. The returned location may be quite old in some circumstances, so the age of the + * location should always be checked. * * @param provider the name of the provider - * @return the last known location for the provider, or null - * + * @return the last known location for the given provider, or null if not available * @throws SecurityException if no suitable permission is present * @throws IllegalArgumentException if provider is null or doesn't exist */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) @Nullable public Location getLastKnownLocation(@NonNull String provider) { - checkProvider(provider); - String packageName = mContext.getPackageName(); + Preconditions.checkArgument(provider != null, "invalid null provider"); + LocationRequest request = LocationRequest.createFromDeprecatedProvider( provider, 0, 0, true); try { - return mService.getLastLocation(request, packageName); + return mService.getLastLocation(request, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -554,7 +545,7 @@ public class LocationManager { * Register for a single location update using the named provider and * a callback. * - * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} * for more detail on how to use this method. * * @param provider the name of the provider with which to register @@ -568,12 +559,16 @@ public class LocationManager { * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present + * @deprecated This method can drain much more battery than expected if it is not possible to + * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit + * removal. */ + @Deprecated @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestSingleUpdate( @NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) { - checkProvider(provider); - checkListener(listener); + Preconditions.checkArgument(provider != null, "invalid null provider"); + Preconditions.checkArgument(listener != null, "invalid null listener"); LocationRequest request = LocationRequest.createFromDeprecatedProvider( provider, 0, 0, true); @@ -599,14 +594,17 @@ public class LocationManager { * @throws IllegalArgumentException if criteria is null * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present + * @deprecated This method can drain much more battery than expected if it is not possible to + * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit + * removal. */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestSingleUpdate( @NonNull Criteria criteria, @NonNull LocationListener listener, @Nullable Looper looper) { - checkCriteria(criteria); - checkListener(listener); + Preconditions.checkArgument(criteria != null, "invalid null criteria"); + Preconditions.checkArgument(listener != null, "invalid null listener"); LocationRequest request = LocationRequest.createFromDeprecatedCriteria( criteria, 0, 0, true); @@ -625,10 +623,13 @@ public class LocationManager { * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if intent is null * @throws SecurityException if no suitable permission is present + * @deprecated This method can drain much more battery than expected if it is not possible to + * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit + * removal. */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String provider, @NonNull PendingIntent intent) { - checkProvider(provider); + Preconditions.checkArgument(provider != null, "invalid null provider"); checkPendingIntent(intent); LocationRequest request = LocationRequest.createFromDeprecatedProvider( @@ -649,10 +650,13 @@ public class LocationManager { * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if intent is null * @throws SecurityException if no suitable permission is present + * @deprecated This method can drain much more battery than expected if it is not possible to + * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit + * removal. */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull Criteria criteria, @NonNull PendingIntent intent) { - checkCriteria(criteria); + Preconditions.checkArgument(criteria != null, "invalid null criteria"); checkPendingIntent(intent); LocationRequest request = LocationRequest.createFromDeprecatedCriteria( @@ -661,84 +665,121 @@ public class LocationManager { } /** - * Register for location updates using the named provider, and a - * pending intent. - * - * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} - * for more detail on how to use this method. + * Register for location updates from the given provider with the given arguments. {@link + * LocationListener} callbacks will take place on the given {@link Looper} or {@link Executor}. + * If a null {@link Looper} is supplied, the Looper of the calling thread will be used instead. + * Only one request can be registered for each unique listener, so any subsequent requests with + * the same listener will overwrite all associated arguments. + * + * <p> It may take a while to receive the first location update. If an immediate location is + * required, applications may use the {@link #getLastKnownLocation(String)} method. + * + * <p> The location update interval can be controlled using the minimum time parameter. The + * elapsed time between location updates will never be less than this parameter, although it may + * be more depending on location availability and other factors. Choosing a sensible value for + * the minimum time parameter is important to conserve battery life. Every location update + * requires power from a variety of sensors. Select a minimum time parameter as high as possible + * while still providing a reasonable user experience. If your application is not in the + * foreground and showing location to the user then your application should consider switching + * to the {@link #PASSIVE_PROVIDER} instead. + * + * <p> The minimum distance parameter can also be used to control the frequency of location + * updates. If it is greater than 0 then the location provider will only send your application + * an update when the location has changed by at least minDistance meters, AND when the minimum + * time has elapsed. However it is more difficult for location providers to save power using the + * minimum distance parameter, so the minimum time parameter should be the primary tool for + * conserving battery life. + * + * <p> If your application wants to passively observe location updates triggered by other + * applications, but not consume any additional power otherwise, then use the {@link + * #PASSIVE_PROVIDER}. This provider does not turn on or modify active location providers, so + * you do not need to be as careful about minimum time and minimum distance parameters. However, + * if your application performs heavy work on a location update (such as network activity) then + * you should select non-zero values for the parameters to rate-limit your update frequency in + * the case another application enables a location provider with extremely fast updates. + * + * <p>In case the provider you have selected is disabled, location updates will cease, and a + * provider availability update will be sent. As soon as the provider is enabled again, another + * provider availability update will be sent and location updates will immediately resume. + * + * <p> When location callbacks are invoked, the system will hold a wakelock on your + * application's behalf for some period of time, but not indefinitely. If your application + * requires a long running wakelock within the location callback, you should acquire it + * yourself. + * + * <p class="note"> Prior to Jellybean, the minTime parameter was only a hint, and some location + * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for + * Android compatible devices to observe both the minTime and minDistance parameters. + * + * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}. * * @param provider the name of the provider with which to register - * @param minTime minimum time interval between location updates, in milliseconds - * @param minDistance minimum distance between location updates, in meters - * @param listener a {@link LocationListener} whose - * {@link LocationListener#onLocationChanged} method will be called for - * each location update + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param listener the listener to receive location updates * * @throws IllegalArgumentException if provider is null or doesn't exist - * on this device * @throws IllegalArgumentException if listener is null * @throws RuntimeException if the calling thread has no Looper * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance, + public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM, @NonNull LocationListener listener) { - checkProvider(provider); - checkListener(listener); + Preconditions.checkArgument(provider != null, "invalid null provider"); + Preconditions.checkArgument(listener != null, "invalid null listener"); LocationRequest request = LocationRequest.createFromDeprecatedProvider( - provider, minTime, minDistance, false); + provider, minTimeMs, minDistanceM, false); requestLocationUpdates(request, listener, null); } /** * Register for location updates using the named provider, and a callback on - * the specified looper thread. + * the specified {@link Looper}. * - * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} - * for more detail on how to use this method. + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. * * @param provider the name of the provider with which to register - * @param minTime minimum time interval between location updates, in milliseconds - * @param minDistance minimum distance between location updates, in meters - * @param listener a {@link LocationListener} whose - * {@link LocationListener#onLocationChanged} method will be called for - * each location update - * @param looper a Looper object whose message queue will be used to - * implement the callback mechanism, or null to make callbacks on the calling - * thread + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param listener the listener to receive location updates + * @param looper the looper handling listener callbacks, or null to use the looper of the + * calling thread * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance, + public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM, @NonNull LocationListener listener, @Nullable Looper looper) { - checkProvider(provider); - checkListener(listener); + Preconditions.checkArgument(provider != null, "invalid null provider"); + Preconditions.checkArgument(listener != null, "invalid null listener"); LocationRequest request = LocationRequest.createFromDeprecatedProvider( - provider, minTime, minDistance, false); + provider, minTimeMs, minDistanceM, false); requestLocationUpdates(request, listener, looper); } /** - * Register for location updates from the given provider with the given arguments. {@link - * LocationListener} callbacks will take place on the given {@link Executor}. Only one request - * can be registered for each unique listener, so any subsequent requests with the same listener - * will overwrite all associated arguments. - * - * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for - * more information. - * - * @param provider the name of the provider used for location updates - * @param minTimeMs minimum time interval between location updates, in milliseconds - * @param minDistanceM minimum distance between location updates, in meters - * @param executor all listener updates will take place on this {@link Executor} - * @param listener a {@link LocationListener} that will be called when updates are available - * @throws IllegalArgumentException if provider, listener, or looper is null or nonexistant - * @throws SecurityException if no suitable permission is present + * Register for location updates using the named provider, and a callback on + * the specified {@link Executor}. + * + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. + * + * @param provider the name of the provider with which to register + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param executor the executor handling listener callbacks + * @param listener the listener to receive location updates + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if executor is null + * @throws IllegalArgumentException if listener is null + * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestLocationUpdates( @@ -753,50 +794,49 @@ public class LocationManager { } /** - * Register for location updates using a Criteria, and a callback - * on the specified looper thread. + * Register for location updates using a provider selected through the given Criteria, and a + * callback on the specified {@link Looper}. * - * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} - * for more detail on how to use this method. + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. * - * @param minTime minimum time interval between location updates, in milliseconds - * @param minDistance minimum distance between location updates, in meters - * @param criteria contains parameters for the location manager to choose the - * appropriate provider and parameters to compute the location - * @param listener a {@link LocationListener} whose - * {@link LocationListener#onLocationChanged} method will be called for - * each location update - * @param looper a Looper object whose message queue will be used to - * implement the callback mechanism, or null to make callbacks on the calling - * thread + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param criteria contains parameters to choose the appropriate provider for location updates + * @param listener the listener to receive location updates * * @throws IllegalArgumentException if criteria is null * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - public void requestLocationUpdates(long minTime, float minDistance, @NonNull Criteria criteria, - @NonNull LocationListener listener, @Nullable Looper looper) { - checkCriteria(criteria); - checkListener(listener); + public void requestLocationUpdates(long minTimeMs, float minDistanceM, + @NonNull Criteria criteria, @NonNull LocationListener listener, + @Nullable Looper looper) { + Preconditions.checkArgument(criteria != null, "invalid null criteria"); + Preconditions.checkArgument(listener != null, "invalid null listener"); LocationRequest request = LocationRequest.createFromDeprecatedCriteria( - criteria, minTime, minDistance, false); + criteria, minTimeMs, minDistanceM, false); requestLocationUpdates(request, listener, looper); } /** - * Uses the given {@link Criteria} to select a single provider to use for location updates. + * Register for location updates using a provider selected through the given Criteria, and a + * callback on the specified {@link Executor}. + * + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. * - * <p>See {@link #requestLocationUpdates(String, long, float, Executor, LocationListener)} for - * more information. + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param criteria contains parameters to choose the appropriate provider for location updates + * @param executor the executor handling listener callbacks + * @param listener the listener to receive location updates * - * @param minTimeMs minimum time interval between location updates, in milliseconds - * @param minDistanceM minimum distance between location updates, in meters - * @param criteria the {@link Criteria} used to select a provider for location updates - * @param executor all listener updates will take place on this {@link Executor} - * @param listener a {@link LocationListener} that will be called when updates are available - * @throws IllegalArgumentException if criteria, listener, or looper is null + * @throws IllegalArgumentException if criteria is null + * @throws IllegalArgumentException if executor is null + * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) @@ -812,191 +852,81 @@ public class LocationManager { } /** - * Register for location updates using the named provider, and a - * pending intent. + * Register for location updates using the named provider, and callbacks delivered via the + * provided {@link PendingIntent}. * - * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} - * for more detail on how to use this method. + * <p>The delivered pending intents will contain extras with the callback information. The keys + * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See + * the documentation for each respective extra key for information on the values. + * + * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}. + * + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. * * @param provider the name of the provider with which to register - * @param minTime minimum time interval between location updates, in milliseconds - * @param minDistance minimum distance between location updates, in meters - * @param intent a {@link PendingIntent} to be sent for each location update + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param pendingIntent the pending intent to send location updates * * @throws IllegalArgumentException if provider is null or doesn't exist - * on this device - * @throws IllegalArgumentException if intent is null + * @throws IllegalArgumentException if pendingIntent is null * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance, - @NonNull PendingIntent intent) { - checkProvider(provider); - checkPendingIntent(intent); + public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM, + @NonNull PendingIntent pendingIntent) { + Preconditions.checkArgument(provider != null, "invalid null provider"); + checkPendingIntent(pendingIntent); LocationRequest request = LocationRequest.createFromDeprecatedProvider( - provider, minTime, minDistance, false); - requestLocationUpdates(request, intent); + provider, minTimeMs, minDistanceM, false); + requestLocationUpdates(request, pendingIntent); } /** - * Register for location updates using a Criteria and pending intent. - * - * <p>The <code>requestLocationUpdates()</code> and - * <code>requestSingleUpdate()</code> register the current activity to be - * updated periodically by the named provider, or by the provider matching - * the specified {@link Criteria}, with location and status updates. - * - * <p> It may take a while to receive the first location update. If - * an immediate location is required, applications may use the - * {@link #getLastKnownLocation(String)} method. - * - * <p> Location updates are received either by {@link LocationListener} - * callbacks, or by broadcast intents to a supplied {@link PendingIntent}. - * - * <p> If the caller supplied a pending intent, then location updates - * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a - * {@link android.location.Location} value. - * - * <p> The location update interval can be controlled using the minTime parameter. - * The elapsed time between location updates will never be less than - * minTime, although it can be more depending on the Location Provider - * implementation and the update interval requested by other applications. - * - * <p> Choosing a sensible value for minTime is important to conserve - * battery life. Each location update requires power from - * GPS, WIFI, Cell and other radios. Select a minTime value as high as - * possible while still providing a reasonable user experience. - * If your application is not in the foreground and showing - * location to the user then your application should avoid using an active - * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}), - * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes) - * or greater. If your application is in the foreground and showing - * location to the user then it is appropriate to select a faster - * update interval. - * - * <p> The minDistance parameter can also be used to control the - * frequency of location updates. If it is greater than 0 then the - * location provider will only send your application an update when - * the location has changed by at least minDistance meters, AND - * at least minTime milliseconds have passed. However it is more - * difficult for location providers to save power using the minDistance - * parameter, so minTime should be the primary tool to conserving battery - * life. - * - * <p> If your application wants to passively observe location - * updates triggered by other applications, but not consume - * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER} - * This provider does not actively turn on or modify active location - * providers, so you do not need to be as careful about minTime and - * minDistance. However if your application performs heavy work - * on a location update (such as network activity) then you should - * select non-zero values for minTime and/or minDistance to rate-limit - * your update frequency in the case another application enables a - * location provider with extremely fast updates. - * - * <p>In case the provider is disabled by the user, updates will stop, - * and a provider availability update will be sent. - * As soon as the provider is enabled again, - * location updates will immediately resume and a provider availability - * update sent. Providers can also send status updates, at any time, - * with extra's specific to the provider. If a callback was supplied - * then status and availability updates are via - * {@link LocationListener#onProviderDisabled}, - * {@link LocationListener#onProviderEnabled} or - * {@link LocationListener#onStatusChanged}. Alternately, if a - * pending intent was supplied then status and availability updates - * are broadcast intents with extra keys of - * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}. - * - * <p> If a {@link LocationListener} is used but with no Looper specified - * then the calling thread must already - * be a {@link android.os.Looper} thread such as the main thread of the - * calling Activity. If a Looper is specified with a {@link LocationListener} - * then callbacks are made on the supplied Looper thread. - * - * <p> When location callbacks are invoked, the system will hold a wakelock - * on your application's behalf for some period of time, but not - * indefinitely. If your application requires a long running wakelock - * within the location callback, you should acquire it yourself. - * - * <p class="note"> Prior to Jellybean, the minTime parameter was - * only a hint, and some location provider implementations ignored it. - * From Jellybean and onwards it is mandatory for Android compatible - * devices to observe both the minTime and minDistance parameters. - * - * @param minTime minimum time interval between location updates, in milliseconds - * @param minDistance minimum distance between location updates, in meters - * @param criteria contains parameters for the location manager to choose the - * appropriate provider and parameters to compute the location - * @param intent a {@link PendingIntent} to be sent for each location update + * Register for location updates using a provider selected through the given Criteria, and + * callbacks delivered via the provided {@link PendingIntent}. * - * @throws IllegalArgumentException if criteria is null - * @throws IllegalArgumentException if intent is null + * <p>See {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on + * how this method works. + * + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters + * @param criteria contains parameters to choose the appropriate provider for location updates + * @param pendingIntent the pending intent to send location updates + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if pendingIntent is null * @throws SecurityException if no suitable permission is present */ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - public void requestLocationUpdates(long minTime, float minDistance, @NonNull Criteria criteria, - @NonNull PendingIntent intent) { - checkCriteria(criteria); - checkPendingIntent(intent); + public void requestLocationUpdates(long minTimeMs, float minDistanceM, + @NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) { + Preconditions.checkArgument(criteria != null, "invalid null criteria"); + checkPendingIntent(pendingIntent); LocationRequest request = LocationRequest.createFromDeprecatedCriteria( - criteria, minTime, minDistance, false); - requestLocationUpdates(request, intent); + criteria, minTimeMs, minDistanceM, false); + requestLocationUpdates(request, pendingIntent); } /** - * Register for fused location updates using a LocationRequest and callback. - * - * <p>Upon a location update, the system delivers the new {@link Location} to the - * provided {@link LocationListener}, by calling its {@link - * LocationListener#onLocationChanged} method.</p> - * - * <p>The system will automatically select and enable the best providers - * to compute a location for your application. It may use only passive - * locations, or just a single location source, or it may fuse together - * multiple location sources in order to produce the best possible - * result, depending on the quality of service requested in the - * {@link LocationRequest}. - * - * <p>LocationRequest can be null, in which case the system will choose - * default, low power parameters for location updates. You will occasionally - * receive location updates as available, without a major power impact on the - * system. If your application just needs an occasional location update - * without any strict demands, then pass a null LocationRequest. + * Register for location updates using a {@link LocationRequest}, and a callback on the + * specified {@link Looper}. * - * <p>Only one LocationRequest can be registered for each unique callback - * or pending intent. So a subsequent request with the same callback or - * pending intent will over-write the previous LocationRequest. + * <p>The system will automatically select and enable the best provider based on the given + * {@link LocationRequest}. The LocationRequest can be null, in which case the system will + * choose default low power parameters for location updates, but this is heavily discouraged, + * and an explicit LocationRequest should always be provided. * - * <p> If a pending intent is supplied then location updates - * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a - * {@link android.location.Location} value. If a callback is supplied - * then location updates are made using the - * {@link LocationListener#onLocationChanged} callback, on the specified - * Looper thread. If a {@link LocationListener} is used - * but with a null Looper then the calling thread must already - * be a {@link android.os.Looper} thread (such as the main thread) and - * callbacks will occur on this thread. + * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} + * for more detail on how this method works. * - * <p> Provider status updates and availability updates are deprecated - * because the system is performing provider fusion on the applications - * behalf. So {@link LocationListener#onProviderDisabled}, - * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged} - * will not be called, and intents with extra keys of - * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not - * be received. - * - * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}. - * - * @param locationRequest quality of service required, null for default low power - * @param listener a {@link LocationListener} whose - * {@link LocationListener#onLocationChanged} method will be called when - * the location update is available - * @param looper a Looper object whose message queue will be used to - * implement the callback mechanism, or null to make callbacks on the calling - * thread + * @param locationRequest the location request containing location parameters + * @param listener the listener to receive location updates + * @param looper the looper handling listener callbacks, or null to use the looper of the + * calling thread * * @throws IllegalArgumentException if listener is null * @throws SecurityException if no suitable permission is present @@ -1007,7 +937,7 @@ public class LocationManager { @TestApi @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestLocationUpdates( - @NonNull LocationRequest locationRequest, + @Nullable LocationRequest locationRequest, @NonNull LocationListener listener, @Nullable Looper looper) { requestLocationUpdates(locationRequest, @@ -1016,45 +946,44 @@ public class LocationManager { } /** - * Register for location updates with the given {@link LocationRequest}. + * Register for location updates using a {@link LocationRequest}, and a callback on the + * specified {@link Executor}. * - * <p>See {@link #requestLocationUpdates(String, long, float, Executor, LocationListener)} for - * more information. + * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} for more + * detail on how this method works. + * + * @param locationRequest the location request containing location parameters + * @param executor the executor handling listener callbacks + * @param listener the listener to receive location updates + * + * @throws IllegalArgumentException if executor is null + * @throws IllegalArgumentException if listener is null + * @throws SecurityException if no suitable permission is present * - * @param locationRequest the {@link LocationRequest} being made - * @param executor all listener updates will take place on this {@link Executor} - * @param listener a {@link LocationListener} that will be called when updates are - * available - * @throws IllegalArgumentException if locationRequest, listener, or executor is null - * @throws SecurityException if no suitable permission is present * @hide */ @SystemApi @TestApi @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestLocationUpdates( - @NonNull LocationRequest locationRequest, + @Nullable LocationRequest locationRequest, @NonNull @CallbackExecutor Executor executor, @NonNull LocationListener listener) { requestLocationUpdates(locationRequest, new LocationListenerTransport(executor, listener)); } /** - * Register for fused location updates using a LocationRequest and a pending intent. - * - * <p>Upon a location update, the system delivers the new {@link Location} with your provided - * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED} - * in the intent's extras.</p> - * - * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}. + * Register for location updates using a {@link LocationRequest}, and callbacks delivered via + * the provided {@link PendingIntent}. * - * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} - * for more detail. + * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} and + * {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on how + * this method works. * - * @param locationRequest quality of service required, null for default low power - * @param pendingIntent a {@link PendingIntent} to be sent for the location update + * @param locationRequest the location request containing location parameters + * @param pendingIntent the pending intent to send location updates * - * @throws IllegalArgumentException if intent is null + * @throws IllegalArgumentException if pendingIntent is null * @throws SecurityException if no suitable permission is present * * @hide @@ -1063,7 +992,7 @@ public class LocationManager { @TestApi @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void requestLocationUpdates( - @NonNull LocationRequest locationRequest, + @Nullable LocationRequest locationRequest, @NonNull PendingIntent pendingIntent) { Preconditions.checkArgument(locationRequest != null, "invalid null location request"); Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent"); @@ -1080,8 +1009,8 @@ public class LocationManager { } } - private void requestLocationUpdates(LocationRequest request, - LocationListenerTransport transport) { + private void requestLocationUpdates(@Nullable LocationRequest request, + @NonNull LocationListenerTransport transport) { synchronized (mListeners) { LocationListenerTransport oldTransport = mListeners.put(transport.getKey(), transport); if (oldTransport != null) { @@ -1105,31 +1034,41 @@ public class LocationManager { * chipset is in the process of getting the first fix. If the client has cached the location, * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link * #getLastKnownLocation(String)}, the location information is still useful before getting - * the first fix.</p> - * - * <p> Useful in products like Auto. + * the first fix. * - * @param newLocation newly available {@link Location} object - * @return true if update was successful, false if not + * @param location newly available {@link Location} object + * @return true if the location was successfully injected, false otherwise * - * @throws SecurityException if no suitable permission is present + * @throws IllegalArgumentException if location is null + * @throws SecurityException if permissions are not present * * @hide */ @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION}) - public boolean injectLocation(@NonNull Location newLocation) { + public boolean injectLocation(@NonNull Location location) { + if (location == null) { + IllegalArgumentException e = new IllegalArgumentException("invalid null location"); + if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) { + throw e; + } else { + Log.w(TAG, e); + return false; + } + } + try { - return mService.injectLocation(newLocation); + return mService.injectLocation(location); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Removes location updates for the specified LocationListener. Following this call, updates - * will no longer occur for this listener. + * Removes location updates for the specified {@link LocationListener}. Following this call, + * the listener will no longer receive location updates. * * @param listener listener that no longer needs location updates + * * @throws IllegalArgumentException if listener is null */ public void removeUpdates(@NonNull LocationListener listener) { @@ -1151,10 +1090,11 @@ public class LocationManager { } /** - * Removes all location updates for the specified pending intent. Following this call, updates - * will no longer occur for this pending intent. + * Removes location updates for the specified {@link PendingIntent}. Following this call, the + * PendingIntent will no longer receive location updates. * * @param pendingIntent pending intent that no longer needs location updates + * * @throws IllegalArgumentException if pendingIntent is null */ public void removeUpdates(@NonNull PendingIntent pendingIntent) { @@ -1168,11 +1108,11 @@ public class LocationManager { } /** - * Returns a list of the names of all known location providers. - * <p>All providers are returned, including ones that are not permitted to - * be accessed by the calling activity or are currently disabled. + * Returns a list of the names of all known location providers. All providers are returned, + * including ones that are not permitted to be accessed by the calling activity or are currently + * disabled. * - * @return list of Strings containing names of the provider + * @return list of provider names */ public @NonNull List<String> getAllProviders() { try { @@ -1183,11 +1123,11 @@ public class LocationManager { } /** - * Returns a list of the names of location providers. + * Returns a list of the names of location providers. Only providers that the caller has + * permission to access will be returned. * - * @param enabledOnly if true then only the providers which are currently - * enabled are returned. - * @return list of Strings containing names of the providers + * @param enabledOnly if true then only enabled providers are included + * @return list of provider names */ public @NonNull List<String> getProviders(boolean enabledOnly) { try { @@ -1198,17 +1138,18 @@ public class LocationManager { } /** - * Returns a list of the names of LocationProviders that satisfy the given - * criteria, or null if none do. Only providers that are permitted to be - * accessed by the calling activity will be returned. + * Returns a list of the names of providers that satisfy the given criteria. Only providers that + * the caller has permission to access will be returned. + * + * @param criteria the criteria that providers must match + * @param enabledOnly if true then only enabled providers are included + * @return list of provider names * - * @param criteria the criteria that the returned providers must match - * @param enabledOnly if true then only the providers which are currently - * enabled are returned. - * @return list of Strings containing names of the providers + * @throws IllegalArgumentException if criteria is null */ public @NonNull List<String> getProviders(@NonNull Criteria criteria, boolean enabledOnly) { - checkCriteria(criteria); + Preconditions.checkArgument(criteria != null, "invalid null criteria"); + try { return mService.getProviders(criteria, enabledOnly); } catch (RemoteException e) { @@ -1217,11 +1158,10 @@ public class LocationManager { } /** - * Returns the name of the provider that best meets the given criteria. Only providers - * that are permitted to be accessed by the calling activity will be - * returned. If several providers meet the criteria, the one with the best - * accuracy is returned. If no provider meets the criteria, - * the criteria are loosened in the following sequence: + * Returns the name of the provider that best meets the given criteria. Only providers that are + * permitted to be accessed by the caller will be returned. If several providers meet the + * criteria, the one with the best accuracy is returned. If no provider meets the criteria, the + * criteria are loosened in the following order: * * <ul> * <li> power requirement @@ -1231,15 +1171,17 @@ public class LocationManager { * <li> altitude * </ul> * - * <p> Note that the requirement on monetary cost is not removed - * in this process. + * <p> Note that the requirement on monetary cost is not removed in this process. * * @param criteria the criteria that need to be matched - * @param enabledOnly if true then only a provider that is currently enabled is returned - * @return name of the provider that best matches the requirements + * @param enabledOnly if true then only enabled providers are included + * @return name of the provider that best matches the criteria, or null if none match + * + * @throws IllegalArgumentException if criteria is null */ public @Nullable String getBestProvider(@NonNull Criteria criteria, boolean enabledOnly) { - checkCriteria(criteria); + Preconditions.checkArgument(criteria != null, "invalid null criteria"); + try { return mService.getBestProvider(criteria, enabledOnly); } catch (RemoteException e) { @@ -1248,24 +1190,22 @@ public class LocationManager { } /** - * Returns the information associated with the location provider of the - * given name, or null if no provider exists by that name. + * Returns the information about the location provider with the given name, or null if no + * provider exists by that name. * - * @param name the provider name - * @return a LocationProvider, or null + * @param provider the provider name + * @return location provider information, or null if provider does not exist * - * @throws IllegalArgumentException if name is null or does not exist - * @throws SecurityException if the caller is not permitted to access the - * given provider. + * @throws IllegalArgumentException if provider is null */ - public @Nullable LocationProvider getProvider(@NonNull String name) { - checkProvider(name); + public @Nullable LocationProvider getProvider(@NonNull String provider) { + Preconditions.checkArgument(provider != null, "invalid null provider"); try { - ProviderProperties properties = mService.getProviderProperties(name); + ProviderProperties properties = mService.getProviderProperties(provider); if (properties == null) { return null; } - return new LocationProvider(name, properties); + return new LocationProvider(provider, properties); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1292,10 +1232,10 @@ public class LocationManager { * Sends additional commands to a location provider. Can be used to support provider specific * extensions to the Location Manager API. * - * @param provider name of the location provider. - * @param command name of the command to send to the provider. - * @param extras optional arguments for the command (or null). - * @return true always + * @param provider name of the location provider + * @param command name of the command to send to the provider + * @param extras optional arguments for the command, or null + * @return true always, the return value may be ignored */ public boolean sendExtraCommand( @NonNull String provider, @NonNull String command, @Nullable Bundle extras) { @@ -1469,7 +1409,7 @@ public class LocationManager { @TestApi @NonNull public List<LocationRequest> getTestProviderCurrentRequests(String providerName) { - checkProvider(providerName); + Preconditions.checkArgument(providerName != null, "invalid null provider"); try { return mService.getTestProviderCurrentRequests(providerName, mContext.getOpPackageName()); @@ -1558,10 +1498,9 @@ public class LocationManager { */ public void removeProximityAlert(@NonNull PendingIntent intent) { checkPendingIntent(intent); - String packageName = mContext.getPackageName(); try { - mService.removeGeofence(null, intent, packageName); + mService.removeGeofence(null, intent, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1609,7 +1548,7 @@ public class LocationManager { @NonNull Geofence fence, @NonNull PendingIntent intent) { checkPendingIntent(intent); - checkGeofence(fence); + Preconditions.checkArgument(fence != null, "invalid null geofence"); try { mService.requestGeofence(request, fence, intent, mContext.getPackageName()); @@ -1636,11 +1575,10 @@ public class LocationManager { */ public void removeGeofence(@NonNull Geofence fence, @NonNull PendingIntent intent) { checkPendingIntent(intent); - checkGeofence(fence); - String packageName = mContext.getPackageName(); + Preconditions.checkArgument(fence != null, "invalid null geofence"); try { - mService.removeGeofence(fence, intent, packageName); + mService.removeGeofence(fence, intent, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1659,10 +1597,9 @@ public class LocationManager { */ public void removeAllGeofences(@NonNull PendingIntent intent) { checkPendingIntent(intent); - String packageName = mContext.getPackageName(); try { - mService.removeGeofence(null, intent, packageName); + mService.removeGeofence(null, intent, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1723,15 +1660,16 @@ public class LocationManager { } /** - * Retrieves information about the current status of the GPS engine. - * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} - * callback to ensure that the data is copied atomically. + * Retrieves information about the current status of the GPS engine. This should only be called + * from within the {@link GpsStatus.Listener#onGpsStatusChanged} callback to ensure that the + * data is copied atomically. * - * The caller may either pass in a {@link GpsStatus} object to set with the latest - * status information, or pass null to create a new {@link GpsStatus} object. + * The caller may either pass in an existing {@link GpsStatus} object to be overwritten, or pass + * null to create a new {@link GpsStatus} object. * * @param status object containing GPS status details, or null. * @return status object containing updated GPS status. + * * @deprecated GpsStatus APIs are deprecated, use {@link GnssStatus} APIs instead. */ @Deprecated @@ -1756,12 +1694,21 @@ public class LocationManager { * @param listener GPS status listener object to register * @return true if the listener was successfully added * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + * * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead. No longer * supported in apps targeting R and above. */ @Deprecated @RequiresPermission(ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(GpsStatus.Listener listener) { + UnsupportedOperationException ex = new UnsupportedOperationException( + "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead"); + if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) { + throw ex; + } else { + Log.w(TAG, ex); + } + try { return mGnssStatusListenerManager.addListener(listener, new Handler()); } catch (RemoteException e) { @@ -1773,11 +1720,20 @@ public class LocationManager { * Removes a GPS status listener. * * @param listener GPS status listener object to remove + * * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead. No longer * supported in apps targeting R and above. */ @Deprecated public void removeGpsStatusListener(GpsStatus.Listener listener) { + UnsupportedOperationException ex = new UnsupportedOperationException( + "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead"); + if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) { + throw ex; + } else { + Log.w(TAG, ex); + } + try { mGnssStatusListenerManager.removeListener(listener); } catch (RemoteException e) { @@ -1790,7 +1746,9 @@ public class LocationManager { * * @param callback GNSS status callback object to register * @return true if the listener was successfully added + * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + * * @deprecated Use {@link #registerGnssStatusCallback(GnssStatus.Callback, Handler)} or {@link * #registerGnssStatusCallback(Executor, GnssStatus.Callback)} instead. */ @@ -1804,8 +1762,9 @@ public class LocationManager { * Registers a GNSS status callback. * * @param callback GNSS status callback object to register - * @param handler a handler with a looper that the callback runs on. + * @param handler a handler with a looper that the callback runs on * @return true if the listener was successfully added + * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present */ @RequiresPermission(ACCESS_FINE_LOCATION) @@ -1826,8 +1785,9 @@ public class LocationManager { * Registers a GNSS status callback. * * @param callback GNSS status callback object to register - * @param executor the executor that the callback runs on. + * @param executor the executor that the callback runs on * @return true if the listener was successfully added + * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present */ @RequiresPermission(ACCESS_FINE_LOCATION) @@ -1855,13 +1815,8 @@ public class LocationManager { } /** - * Adds an NMEA listener. - * - * @param listener a {@link GpsStatus.NmeaListener} object to register - * - * @return true if the listener was successfully added + * No-op method to keep backward-compatibility. * - * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead. * @removed */ @@ -1872,9 +1827,8 @@ public class LocationManager { } /** - * Removes an NMEA listener. + * No-op method to keep backward-compatibility. * - * @param listener a {@link GpsStatus.NmeaListener} object to remove * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead. * @removed */ @@ -1951,30 +1905,26 @@ public class LocationManager { /** * No-op method to keep backward-compatibility. - * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead. + * * @hide - * @deprecated Not supported anymore. + * @deprecated Use {@link #registerGnssMeasurementsCallback} instead. * @removed */ @Deprecated @SystemApi - @SuppressLint("Doclava125") public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) { return false; } /** - * No-op method to keep backward-compatibility. Don't use it. Use {@link - * #unregisterGnssMeasurementsCallback} instead. + * No-op method to keep backward-compatibility. * * @hide - * @deprecated use {@link #unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback)} - * instead. + * @deprecated Use {@link #unregisterGnssMeasurementsCallback} instead. * @removed */ @Deprecated @SystemApi - @SuppressLint("Doclava125") public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {} /** @@ -2067,30 +2017,26 @@ public class LocationManager { /** * No-op method to keep backward-compatibility. - * Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead. + * * @hide - * @deprecated Not supported anymore. + * @deprecated Use {@link #registerGnssNavigationMessageCallback} instead. * @removed */ @Deprecated @SystemApi - @SuppressLint("Doclava125") public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) { return false; } /** * No-op method to keep backward-compatibility. - * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead. + * * @hide - * @deprecated use - * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)} - * instead + * @deprecated Use {@link #unregisterGnssNavigationMessageCallback} instead. * @removed */ @Deprecated @SystemApi - @SuppressLint("Doclava125") public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {} /** @@ -2276,31 +2222,11 @@ public class LocationManager { } } - private static void checkProvider(String provider) { - if (provider == null) { - throw new IllegalArgumentException("invalid provider: " + provider); - } - } - - private static void checkCriteria(Criteria criteria) { - if (criteria == null) { - throw new IllegalArgumentException("invalid criteria: " + criteria); - } - } - - private static void checkListener(LocationListener listener) { - if (listener == null) { - throw new IllegalArgumentException("invalid listener: " + listener); - } - } - - private void checkPendingIntent(PendingIntent intent) { - if (intent == null) { - throw new IllegalArgumentException("invalid pending intent: " + intent); - } - if (!intent.isTargetedToPackage()) { + private void checkPendingIntent(PendingIntent pendingIntent) { + Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent"); + if (!pendingIntent.isTargetedToPackage()) { IllegalArgumentException e = new IllegalArgumentException( - "pending intent must be targeted to package"); + "invalid pending intent - must be targeted to package"); if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) { throw e; } else { @@ -2309,12 +2235,6 @@ public class LocationManager { } } - private static void checkGeofence(Geofence fence) { - if (fence == null) { - throw new IllegalArgumentException("invalid geofence: " + fence); - } - } - private class LocationListenerTransport extends ILocationListener.Stub { private final Executor mExecutor; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2d6cd242c702..f797da70e7d1 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1857,12 +1857,37 @@ public class AudioManager { } /** + * @hide + * Sets the microphone from switch mute on or off. + * <p> + * This method should only be used by InputManager to notify + * Audio Subsystem about Microphone Mute switch state. + * + * @param on set <var>true</var> to mute the microphone; + * <var>false</var> to turn mute off + */ + @UnsupportedAppUsage + public void setMicrophoneMuteFromSwitch(boolean on) { + final IAudioService service = getService(); + try { + service.setMicrophoneMuteFromSwitch(on); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Checks whether the microphone mute is on or off. * * @return true if microphone is muted, false if it's not */ public boolean isMicrophoneMute() { - return AudioSystem.isMicrophoneMuted(); + final IAudioService service = getService(); + try { + return service.isMicrophoneMuted(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 71f52a1b7d8e..fc056109baa4 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -106,8 +106,12 @@ interface IAudioService { List<AudioProductStrategy> getAudioProductStrategies(); + boolean isMicrophoneMuted(); + void setMicrophoneMute(boolean on, String callingPackage, int userId); + oneway void setMicrophoneMuteFromSwitch(boolean on); + void setRingerModeExternal(int ringerMode, String caller); void setRingerModeInternal(int ringerMode, String caller); diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 1b713b6ab74b..81213b943c81 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -40,6 +40,7 @@ interface IMediaRouterService { void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); + void setControlCategories(IMediaRouterClient client, in List<String> categories); // Methods for media router 2 void registerClient2(IMediaRouter2Client client, String packageName); @@ -52,7 +53,7 @@ interface IMediaRouterService { * @param route the route to be selected */ void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route); - void setControlCategories(IMediaRouter2Client client, in List<String> categories); + void setControlCategories2(IMediaRouter2Client client, in List<String> categories); void registerManager(IMediaRouter2Manager manager, String packageName); void unregisterManager(IMediaRouter2Manager manager); diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 8887c7c57ccb..09221a37cb13 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.mtp.MtpConstants; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.HashMap; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index d72231f40dcf..9cb78696f19b 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -49,6 +49,8 @@ import android.view.Display; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -82,6 +84,7 @@ public class MediaRouter { final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); + List<String> mControlCategories = Collections.emptyList(); final RouteCategory mSystemCategory; @@ -358,6 +361,18 @@ public class MediaRouter { return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); } + public void setControlCategories(Collection<String> controlCategories) { + List<String> newControlCategories = new ArrayList<>(controlCategories); + mControlCategories = newControlCategories; + if (mClient != null) { + try { + mMediaRouterService.setControlCategories(mClient, newControlCategories); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to set control categories.", ex); + } + } + } + private void updatePresentationDisplays(int changedDisplayId) { final int count = mRoutes.size(); for (int i = 0; i < count; i++) { @@ -406,6 +421,7 @@ public class MediaRouter { try { Client client = new Client(); mMediaRouterService.registerClientAsUser(client, mPackageName, userId); + mMediaRouterService.setControlCategories(client, mControlCategories); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router client.", ex); @@ -1302,6 +1318,19 @@ public class MediaRouter { sStatic.rebindAsUser(userId); } + /** + * Sets the control categories of the application. + * Routes that support at least one of the given control categories only exists and are handled + * by the media router. + * + * @hide + */ + public void setControlCategories(@NonNull Collection<String> controlCategories) { + Objects.requireNonNull(controlCategories, "control categories must not be null"); + + sStatic.setControlCategories(controlCategories); + } + static void updateRoute(final RouteInfo info) { dispatchRouteChanged(info); } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 8e29e34caa14..ed35ef6a7ac7 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -129,7 +129,7 @@ public class MediaRouter2 { Client client = new Client(); try { mMediaRouterService.registerClient2(client, mPackageName); - mMediaRouterService.setControlCategories(client, mControlCategories); + mMediaRouterService.setControlCategories2(client, mControlCategories); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router.", ex); @@ -188,7 +188,7 @@ public class MediaRouter2 { } if (client != null) { try { - mMediaRouterService.setControlCategories(client, newControlCategories); + mMediaRouterService.setControlCategories2(client, newControlCategories); } catch (RemoteException ex) { Log.e(TAG, "Unable to set control categories.", ex); } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 6257feb2f894..45ee210c80c9 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -59,7 +59,10 @@ cc_library_shared { "android.hidl.token@1.0-utils", ], - header_libs: ["libhardware_headers"], + header_libs: [ + "libhardware_headers", + "libmediadrm_headers", + ], static_libs: ["libgrallocusage"], diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index 5ebac1d61648..684069b0120a 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -20,15 +20,12 @@ #include "jni.h" #include <media/stagefright/foundation/ABase.h> -#include <media/IDrm.h> -#include <media/IDrmClient.h> +#include <mediadrm/IDrm.h> #include <utils/Errors.h> #include <utils/RefBase.h> namespace android { -struct IDrm; - class DrmListener: virtual public RefBase { public: diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java index 38f0175579ad..481f4796951d 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java @@ -31,7 +31,7 @@ import android.mtp.MtpConstants; import androidx.test.runner.AndroidJUnit4; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java index 3abf0a4941e6..a3ed07a6dee3 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.Intent; import android.media.MediaRoute2Info; +import android.media.MediaRouter; import android.media.MediaRouter2; import android.media.MediaRouter2Manager; import android.support.test.InstrumentationRegistry; @@ -72,7 +73,8 @@ public class MediaRouterManagerTest { private Context mContext; private MediaRouter2Manager mManager; - private MediaRouter2 mRouter; + private MediaRouter mRouter; + private MediaRouter2 mRouter2; private Executor mExecutor; private String mPackageName; @@ -89,7 +91,8 @@ public class MediaRouterManagerTest { public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); mManager = MediaRouter2Manager.getInstance(mContext); - mRouter = MediaRouter2.getInstance(mContext); + mRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); + mRouter2 = MediaRouter2.getInstance(mContext); //TODO: If we need to support thread pool executors, change this to thread pool executor. mExecutor = Executors.newSingleThreadExecutor(); mPackageName = mContext.getPackageName(); @@ -131,12 +134,12 @@ public class MediaRouterManagerTest { //TODO: Figure out a more proper way to test. // (Control requests shouldn't be used in this way.) - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, mockRouterCallback); - mRouter.sendControlRequest( + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); + mRouter2.sendControlRequest( new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(), new Intent(ACTION_REMOVE_ROUTE)); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); verify(mockCallback, timeout(TIMEOUT_MS)).onRouteRemoved(argThat( (MediaRoute2Info info) -> @@ -148,15 +151,41 @@ public class MediaRouterManagerTest { * Tests if we get proper routes for application that has special control category. */ @Test + public void testControlCategoryWithMediaRouter() throws Exception { + MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); + mManager.registerCallback(mExecutor, mockCallback); + + MediaRouter.Callback mockRouterCallback = mock(MediaRouter.Callback.class); + + mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter.addCallback(MediaRouter.ROUTE_TYPE_USER, mockRouterCallback); + + verify(mockCallback, timeout(TIMEOUT_MS)) + .onRoutesChanged(argThat(routes -> routes.size() > 0)); + + Map<String, MediaRoute2Info> routes = + createRouteMap(mManager.getAvailableRoutes(mPackageName)); + + Assert.assertEquals(1, routes.size()); + Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); + + mRouter.removeCallback(mockRouterCallback); + mManager.unregisterCallback(mockCallback); + } + + /** + * Tests if we get proper routes for application that has special control category. + */ + @Test public void testControlCategory() throws Exception { MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); mManager.registerCallback(mExecutor, mockCallback); MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class); - mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); - mRouter.registerCallback(mExecutor, mockRouterCallback); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); verify(mockCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -177,15 +206,15 @@ public class MediaRouterManagerTest { public void testGetRoutes() throws Exception { MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); - mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); - mRouter.registerCallback(mExecutor, mockCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter2.registerCallback(mExecutor, mockCallback); verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce()) .onRoutesChanged(argThat(routes -> routes.size() > 0)); - Map<String, MediaRoute2Info> routes = createRouteMap(mRouter.getRoutes()); + Map<String, MediaRoute2Info> routes = createRouteMap(mRouter2.getRoutes()); Assert.assertEquals(1, routes.size()); Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); - mRouter.unregisterCallback(mockCallback); + mRouter2.unregisterCallback(mockCallback); } @Test @@ -194,8 +223,8 @@ public class MediaRouterManagerTest { MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class); mManager.registerCallback(mExecutor, managerCallback); - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, mockRouterCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); verify(managerCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -211,7 +240,7 @@ public class MediaRouterManagerTest { .onRouteAdded(argThat(route -> route.equals(routeToSelect))); mManager.unregisterCallback(managerCallback); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); } /** @@ -223,8 +252,8 @@ public class MediaRouterManagerTest { MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class); mManager.registerCallback(mExecutor, managerCallback); - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, routerCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, routerCallback); verify(managerCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -248,7 +277,7 @@ public class MediaRouterManagerTest { .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId()) && TextUtils.equals(routeInfo.getClientPackageName(), null))); - mRouter.unregisterCallback(routerCallback); + mRouter2.unregisterCallback(routerCallback); mManager.unregisterCallback(managerCallback); } diff --git a/mime/Android.bp b/mime/Android.bp index 17bad746e039..8b2b05958b6f 100644 --- a/mime/Android.bp +++ b/mime/Android.bp @@ -12,23 +12,83 @@ // See the License for the specific language governing permissions and // limitations under the License. + +java_defaults { + name: "mimemap-defaults", + srcs: [ + "java/android/content/type/DefaultMimeMapFactory.java", + ], + sdk_version: "core_platform", +} + java_library { name: "mimemap", + defaults: ["mimemap-defaults"], + static_libs: ["mimemap-res.jar"], + visibility: [ + "//frameworks/base:__subpackages__", + ], +} + +java_library { + name: "mimemap-testing", + defaults: ["mimemap-defaults"], + static_libs: ["mimemap-testing-res.jar"], + jarjar_rules: "jarjar-rules.txt", visibility: [ "//cts/tests/tests/mimemap:__subpackages__", "//frameworks/base:__subpackages__", ], +} - srcs: [ - "java/android/content/type/DefaultMimeMapFactory.java", +// The mimemap-res.jar and mimemap-testing-res.jar genrules produce a .jar that +// has the resource file in a subdirectory res/ and testres/, respectively. +// They need to be in different paths because one of them ends up in a +// bootclasspath jar whereas the other one ends up in a test jar. Bootclasspath +// resources hide test or application resources under the same path because +// ClassLoader.getResource(String) consults the parent ClassLoader first. +// +// Further notes: +// - the "cp" command will flatten any directory paths that occur in $(in), +// but here they happen to already be in the root directory. If we needed +// to preserve sub paths then we might want to zip the files first and then +// unzip them below the new parent directory. +// - the path names "res/" and "testres/" and duplicated in .java source files +// (DefaultMimeMapFactory.java and MimeMapTest.java, as of October 2019). +java_genrule { + name: "mimemap-res.jar", + tools: [ + "soong_zip", ], + srcs: [":mime.types"], + out: ["mimemap-res.jar"], + cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/", +} - java_resources: [ +// The same as mimemap-res.jar except that the resources are placed in a different directory. +// They get bundled with CTS so that CTS can compare a device's MimeMap implementation vs. +// the stock Android one from when CTS was built. +java_genrule { + name: "mimemap-testing-res.jar", + tools: [ + "soong_zip", + ], + srcs: [":mime.types"], + out: ["mimemap-testing-res.jar"], + cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/", +} + +// Combination of all *mime.types resources. +filegroup { + name: "mime.types", + visibility: [ + "//visibility:private", + ], + srcs: [ ":debian.mime.types", ":android.mime.types", + ":vendor.mime.types", ], - - sdk_version: "core_platform", } filegroup { @@ -41,3 +101,14 @@ filegroup { "java-res/android.mime.types", ], } + +filegroup { + name: "vendor.mime.types", + visibility: [ + "//visibility:private", + ], + path: "java-res/", + srcs: [ + "java-res/vendor.mime.types", + ], +} diff --git a/mime/TEST_MAPPING b/mime/TEST_MAPPING new file mode 100644 index 000000000000..8daab754ea8a --- /dev/null +++ b/mime/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsMimeMapTestCases" + } + ] +} diff --git a/mime/jarjar-rules.txt b/mime/jarjar-rules.txt new file mode 100644 index 000000000000..145d1dbf3d11 --- /dev/null +++ b/mime/jarjar-rules.txt @@ -0,0 +1 @@ +rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidMimeMapFactory
\ No newline at end of file diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types index 1ca912e8510b..7a5299ff1b69 100644 --- a/mime/java-res/android.mime.types +++ b/mime/java-res/android.mime.types @@ -3,7 +3,7 @@ # # Android-specific MIME type <-> extension mappings # -# Each line below defines an mapping from one MIME type to the first of the +# Each line below defines a mapping from one MIME type to the first of the # listed extensions, and from listed extension back to the MIME type. # A mapping overrides any previous mapping _from_ that same MIME type or # extension (put() semantics), unless that MIME type / extension is prefixed with '?' diff --git a/mime/java-res/vendor.mime.types b/mime/java-res/vendor.mime.types new file mode 100644 index 000000000000..afb8f9e4ef39 --- /dev/null +++ b/mime/java-res/vendor.mime.types @@ -0,0 +1,41 @@ +############################################################################### +# +# Vendor-specific MIME type <-> extension mappings +# +# Each line below defines a mapping from one MIME type to the first of the +# listed extensions, and from listed extension back to the MIME type. +# +# This file can _add_ additional mappings that are not in the default set, +# but it it cannot _modify_ (replace or remove) any platform default mapping +# (defined in files mime.types and android.mime.types). +# +############################################################################### +# +# EXAMPLES +# +# A line of the form (without the leading '#''): +# +# mime ext1 ext2 ext3 +# +# affects the current mappings along the lines of the following pseudo code: +# +# mimeToExt.putIfAbsent("mime", "ext1"); +# extToMime.putIfAbsent("ext1", "mime"); +# extToMime.putIfAbsent("ext2", "mime"); +# extToMime.putIfAbsent("ext3", "mime"); +# +# Optionally, MIME types or extensions may be prefixed by a single '?', which +# will be ignored. I.e., the following example lines all have the same semantics: +# +# mime ext1 ext2 ext3 +# ?mime ext1 ext2 ext3 +# mime ?ext1 ext2 ?ext3 +# ?mime ?ext1 ?ext2 ?ext3 +# +# By default, this file contains no mappings (which means that the platform +# default mapping is used unmodified). +# +############################################################################### +# +# Add your custom mappings below this line (with no "#" at the start of the line): + diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java index 545fb3cbb5cd..03b685df644e 100644 --- a/mime/java/android/content/type/DefaultMimeMapFactory.java +++ b/mime/java/android/content/type/DefaultMimeMapFactory.java @@ -16,13 +16,17 @@ package android.content.type; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.function.Function; import java.util.regex.Pattern; /** @@ -44,24 +48,33 @@ public class DefaultMimeMapFactory { * Android's default mapping between MIME types and extensions. */ public static MimeMap create() { - return parseFromResources("/mime.types", "/android.mime.types"); + Class c = DefaultMimeMapFactory.class; + // The resources are placed into the res/ path by the "mimemap-res.jar" genrule. + return create(resourceName -> c.getResourceAsStream("/res/" + resourceName)); } private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+"); - static MimeMap parseFromResources(String... resourceNames) { + /** + * Creates a {@link MimeMap} instance whose resources are loaded from the + * InputStreams looked up in {@code resourceSupplier}. + * + * @hide + */ + public static MimeMap create(Function<String, InputStream> resourceSupplier) { MimeMap.Builder builder = MimeMap.builder(); - for (String resourceName : resourceNames) { - parseTypes(builder, resourceName); - } + parseTypes(builder, true, resourceSupplier, "mime.types"); + parseTypes(builder, true, resourceSupplier, "android.mime.types"); + parseTypes(builder, false, resourceSupplier, "vendor.mime.types"); return builder.build(); } - private static void parseTypes(MimeMap.Builder builder, String resource) { - try (BufferedReader r = new BufferedReader( - new InputStreamReader(DefaultMimeMapFactory.class.getResourceAsStream(resource)))) { + private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite, + Function<String, InputStream> resourceSupplier, String resourceName) { + try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName)); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; - while ((line = r.readLine()) != null) { + while ((line = reader.readLine()) != null) { int commentPos = line.indexOf('#'); if (commentPos >= 0) { line = line.substring(0, commentPos); @@ -71,11 +84,28 @@ public class DefaultMimeMapFactory { continue; } List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line)); + if (!allowOverwrite) { + // Pretend that the mimeType and each file extension listed in the line + // carries a "?" prefix, which means that it can add new mappings but + // not modify existing mappings (putIfAbsent() semantics). + specs = ensurePrefix("?", specs); + } builder.put(specs.get(0), specs.subList(1, specs.size())); } } catch (IOException | RuntimeException e) { - throw new RuntimeException("Failed to parse " + resource, e); + throw new RuntimeException("Failed to parse " + resourceName, e); + } + } + + private static List<String> ensurePrefix(String prefix, List<String> strings) { + List<String> result = new ArrayList<>(strings.size()); + for (String s : strings) { + if (!s.startsWith(prefix)) { + s = prefix + s; + } + result.add(s); } + return result; } } diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java new file mode 100644 index 000000000000..619438c7f6fe --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java @@ -0,0 +1,244 @@ +/* + * 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.backup.encryption.tasks; + +import android.annotation.Nullable; +import android.app.backup.BackupDataInput; +import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.security.keystore.recovery.InternalRecoveryServiceException; +import android.security.keystore.recovery.LockScreenRequiredException; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.backup.encryption.CryptoSettings; +import com.android.server.backup.encryption.chunking.ProtoStore; +import com.android.server.backup.encryption.client.CryptoBackupServer; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager; +import com.android.server.backup.encryption.keys.TertiaryKeyManager; +import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.KeyValueListingProto; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.util.Optional; + +// TODO(b/141975695): Create a base class for EncryptedKvBackupTask and EncryptedFullBackupTask. +/** Performs encrypted key value backup, handling rotating the tertiary key as necessary. */ +public class EncryptedKvBackupTask { + private static final String TAG = "EncryptedKvBackupTask"; + + private final TertiaryKeyManager mTertiaryKeyManager; + private final RecoverableKeyStoreSecondaryKey mSecondaryKey; + private final ProtoStore<KeyValueListingProto.KeyValueListing> mKeyValueListingStore; + private final ProtoStore<ChunksMetadataProto.ChunkListing> mChunkListingStore; + private final KvBackupEncrypter mKvBackupEncrypter; + private final EncryptedBackupTask mEncryptedBackupTask; + private final String mPackageName; + + /** Constructs new instances of {@link EncryptedKvBackupTask}. */ + public static class EncryptedKvBackupTaskFactory { + /** + * Creates a new instance. + * + * <p>Either initializes encrypted backup or loads an existing secondary key as necessary. + * + * @param cryptoSettings to load secondary key state from + * @param fileDescriptor to read the backup data from + */ + public EncryptedKvBackupTask newInstance( + Context context, + SecureRandom secureRandom, + CryptoBackupServer cryptoBackupServer, + CryptoSettings cryptoSettings, + RecoverableKeyStoreSecondaryKeyManager + .RecoverableKeyStoreSecondaryKeyManagerProvider + recoverableSecondaryKeyManagerProvider, + ParcelFileDescriptor fileDescriptor, + String packageName) + throws IOException, UnrecoverableKeyException, LockScreenRequiredException, + InternalRecoveryServiceException, InvalidKeyException { + RecoverableKeyStoreSecondaryKey secondaryKey = + new InitializeRecoverableSecondaryKeyTask( + context, + cryptoSettings, + recoverableSecondaryKeyManagerProvider.get(), + cryptoBackupServer) + .run(); + KvBackupEncrypter backupEncrypter = + new KvBackupEncrypter(new BackupDataInput(fileDescriptor.getFileDescriptor())); + TertiaryKeyManager tertiaryKeyManager = + new TertiaryKeyManager( + context, + secureRandom, + TertiaryKeyRotationScheduler.getInstance(context), + secondaryKey, + packageName); + + return new EncryptedKvBackupTask( + tertiaryKeyManager, + ProtoStore.createKeyValueListingStore(context), + secondaryKey, + ProtoStore.createChunkListingStore(context), + backupEncrypter, + new EncryptedBackupTask( + cryptoBackupServer, secureRandom, packageName, backupEncrypter), + packageName); + } + } + + @VisibleForTesting + EncryptedKvBackupTask( + TertiaryKeyManager tertiaryKeyManager, + ProtoStore<KeyValueListingProto.KeyValueListing> keyValueListingStore, + RecoverableKeyStoreSecondaryKey secondaryKey, + ProtoStore<ChunksMetadataProto.ChunkListing> chunkListingStore, + KvBackupEncrypter kvBackupEncrypter, + EncryptedBackupTask encryptedBackupTask, + String packageName) { + mTertiaryKeyManager = tertiaryKeyManager; + mSecondaryKey = secondaryKey; + mKeyValueListingStore = keyValueListingStore; + mChunkListingStore = chunkListingStore; + mKvBackupEncrypter = kvBackupEncrypter; + mEncryptedBackupTask = encryptedBackupTask; + mPackageName = packageName; + } + + /** + * Reads backup data from the file descriptor provided in the construtor, encrypts it and + * uploads it to the server. + * + * <p>The {@code incremental} flag indicates if the backup data provided is incremental or a + * complete set. Incremental backup is not possible if no previous crypto state exists, or the + * tertiary key must be rotated in the next backup. If the caller requests incremental backup + * but it is not possible, then the backup will not start and this method will throw {@link + * NonIncrementalBackupRequiredException}. + * + * <p>TODO(b/70704456): Update return code to indicate that we require non-incremental backup. + * + * @param incremental {@code true} if the data provided is a diff from the previous backup, + * {@code false} if it is a complete set + * @throws NonIncrementalBackupRequiredException if the caller provides an incremental backup but the task + * requires non-incremental backup + */ + public void performBackup(boolean incremental) + throws GeneralSecurityException, IOException, NoSuchMethodException, + InstantiationException, IllegalAccessException, InvocationTargetException, + NonIncrementalBackupRequiredException { + if (mTertiaryKeyManager.wasKeyRotated()) { + Slog.d(TAG, "Tertiary key is new so clearing package state."); + deleteListings(mPackageName); + } + + Optional<Pair<KeyValueListingProto.KeyValueListing, ChunksMetadataProto.ChunkListing>> + oldListings = getListingsAndEnsureConsistency(mPackageName); + + if (oldListings.isPresent() && !incremental) { + Slog.d( + TAG, + "Non-incremental backup requested but incremental state existed, clearing it"); + deleteListings(mPackageName); + oldListings = Optional.empty(); + } + + if (!oldListings.isPresent() && incremental) { + // If we don't have any state then we require a non-incremental backup, but this backup + // is incremental. + throw new NonIncrementalBackupRequiredException(); + } + + if (oldListings.isPresent()) { + mKvBackupEncrypter.setOldKeyValueListing(oldListings.get().first); + } + + ChunksMetadataProto.ChunkListing newChunkListing; + if (oldListings.isPresent()) { + Slog.v(TAG, "Old listings existed, performing incremental backup"); + newChunkListing = + mEncryptedBackupTask.performIncrementalBackup( + mTertiaryKeyManager.getKey(), + mTertiaryKeyManager.getWrappedKey(), + oldListings.get().second); + } else { + Slog.v(TAG, "Old listings did not exist, performing non-incremental backup"); + // kv backups don't use this salt because they don't involve content-defined chunking. + byte[] fingerprintMixerSalt = null; + newChunkListing = + mEncryptedBackupTask.performNonIncrementalBackup( + mTertiaryKeyManager.getKey(), + mTertiaryKeyManager.getWrappedKey(), + fingerprintMixerSalt); + } + + Slog.v(TAG, "Backup and upload succeeded, saving new listings"); + saveListings(mPackageName, mKvBackupEncrypter.getNewKeyValueListing(), newChunkListing); + } + + private Optional<Pair<KeyValueListingProto.KeyValueListing, ChunksMetadataProto.ChunkListing>> + getListingsAndEnsureConsistency(String packageName) + throws IOException, InvocationTargetException, NoSuchMethodException, + InstantiationException, IllegalAccessException { + Optional<KeyValueListingProto.KeyValueListing> keyValueListing = + mKeyValueListingStore.loadProto(packageName); + Optional<ChunksMetadataProto.ChunkListing> chunkListing = + mChunkListingStore.loadProto(packageName); + + // Normally either both protos exist or neither exist, but we correct this just in case. + boolean bothPresent = keyValueListing.isPresent() && chunkListing.isPresent(); + if (!bothPresent) { + Slog.d( + TAG, + "Both listing were not present, clearing state, key value=" + + keyValueListing.isPresent() + + ", chunk=" + + chunkListing.isPresent()); + deleteListings(packageName); + return Optional.empty(); + } + + return Optional.of(Pair.create(keyValueListing.get(), chunkListing.get())); + } + + private void saveListings( + String packageName, + KeyValueListingProto.KeyValueListing keyValueListing, + ChunksMetadataProto.ChunkListing chunkListing) { + try { + mKeyValueListingStore.saveProto(packageName, keyValueListing); + mChunkListingStore.saveProto(packageName, chunkListing); + } catch (IOException e) { + // If a problem occurred while saving either listing then they may be inconsistent, so + // delete + // both. + Slog.w(TAG, "Unable to save listings, deleting both for consistency", e); + deleteListings(packageName); + } + } + + private void deleteListings(String packageName) { + mKeyValueListingStore.deleteProto(packageName); + mChunkListingStore.deleteProto(packageName); + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.java new file mode 100644 index 000000000000..12b44590ebe6 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.java @@ -0,0 +1,139 @@ +/* + * 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.backup.encryption.tasks; + +import static com.android.internal.util.Preconditions.checkArgument; + +import android.app.backup.BackupDataOutput; +import android.content.Context; +import android.os.ParcelFileDescriptor; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.backup.encryption.FullRestoreDownloader; +import com.android.server.backup.encryption.chunking.ChunkHasher; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager; +import com.android.server.backup.encryption.keys.RestoreKeyFetcher; +import com.android.server.backup.encryption.kv.DecryptedChunkKvOutput; +import com.android.server.backup.encryption.protos.nano.KeyValuePairProto; +import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; + +import java.io.File; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; + +/** + * Performs a key value restore by downloading the backup set, decrypting it and writing it to the + * file provided by backup manager. + */ +public class EncryptedKvRestoreTask { + private static final String ENCRYPTED_FILE_NAME = "encrypted_kv"; + + private final File mTemporaryFolder; + private final ChunkHasher mChunkHasher; + private final FullRestoreToFileTask mFullRestoreToFileTask; + private final BackupFileDecryptorTask mBackupFileDecryptorTask; + + /** Constructs new instances of the task. */ + public static class EncryptedKvRestoreTaskFactory { + /** + * Constructs a new instance. + * + * <p>Fetches the appropriate secondary key and uses this to unwrap the tertiary key. Stores + * temporary files in {@link Context#getFilesDir()}. + */ + public EncryptedKvRestoreTask newInstance( + Context context, + RecoverableKeyStoreSecondaryKeyManager + .RecoverableKeyStoreSecondaryKeyManagerProvider + recoverableSecondaryKeyManagerProvider, + FullRestoreDownloader fullRestoreDownloader, + String secondaryKeyAlias, + WrappedKeyProto.WrappedKey wrappedTertiaryKey) + throws EncryptedRestoreException, NoSuchAlgorithmException, NoSuchPaddingException, + KeyException, InvalidAlgorithmParameterException { + SecretKey tertiaryKey = + RestoreKeyFetcher.unwrapTertiaryKey( + recoverableSecondaryKeyManagerProvider, + secondaryKeyAlias, + wrappedTertiaryKey); + + return new EncryptedKvRestoreTask( + context.getFilesDir(), + new ChunkHasher(tertiaryKey), + new FullRestoreToFileTask(fullRestoreDownloader), + new BackupFileDecryptorTask(tertiaryKey)); + } + } + + @VisibleForTesting + EncryptedKvRestoreTask( + File temporaryFolder, + ChunkHasher chunkHasher, + FullRestoreToFileTask fullRestoreToFileTask, + BackupFileDecryptorTask backupFileDecryptorTask) { + checkArgument( + temporaryFolder.isDirectory(), "Temporary folder must be an existing directory"); + + mTemporaryFolder = temporaryFolder; + mChunkHasher = chunkHasher; + mFullRestoreToFileTask = fullRestoreToFileTask; + mBackupFileDecryptorTask = backupFileDecryptorTask; + } + + /** + * Runs the restore, writing the pairs in lexicographical order to the given file descriptor. + * + * <p>This will block for the duration of the restore. + * + * @throws EncryptedRestoreException if there is a problem decrypting or verifying the backup + */ + public void getRestoreData(ParcelFileDescriptor output) + throws IOException, EncryptedRestoreException, BadPaddingException, + InvalidAlgorithmParameterException, NoSuchAlgorithmException, + IllegalBlockSizeException, ShortBufferException, InvalidKeyException { + File encryptedFile = new File(mTemporaryFolder, ENCRYPTED_FILE_NAME); + try { + downloadDecryptAndWriteBackup(encryptedFile, output); + } finally { + encryptedFile.delete(); + } + } + + private void downloadDecryptAndWriteBackup(File encryptedFile, ParcelFileDescriptor output) + throws EncryptedRestoreException, IOException, BadPaddingException, InvalidKeyException, + NoSuchAlgorithmException, IllegalBlockSizeException, ShortBufferException, + InvalidAlgorithmParameterException { + mFullRestoreToFileTask.restoreToFile(encryptedFile); + DecryptedChunkKvOutput decryptedChunkKvOutput = new DecryptedChunkKvOutput(mChunkHasher); + mBackupFileDecryptorTask.decryptFile(encryptedFile, decryptedChunkKvOutput); + + BackupDataOutput backupDataOutput = new BackupDataOutput(output.getFileDescriptor()); + for (KeyValuePairProto.KeyValuePair pair : decryptedChunkKvOutput.getPairs()) { + backupDataOutput.writeEntityHeader(pair.key, pair.value.length); + backupDataOutput.writeEntityData(pair.value, pair.value.length); + } + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java new file mode 100644 index 000000000000..a3eda7d1270f --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java @@ -0,0 +1,25 @@ +/* + * 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.backup.encryption.tasks; + +// TODO(141840878): Update documentation. +/** + * Exception thrown when the framework provides an incremental backup but the transport requires a + * non-incremental backup. + */ +public class NonIncrementalBackupRequiredException extends Exception {} diff --git a/packages/BackupEncryption/test/robolectric-integration/Android.bp b/packages/BackupEncryption/test/robolectric-integration/Android.bp index f696278ab967..67365df4b28f 100644 --- a/packages/BackupEncryption/test/robolectric-integration/Android.bp +++ b/packages/BackupEncryption/test/robolectric-integration/Android.bp @@ -23,6 +23,7 @@ android_robolectric_test { "platform-test-annotations", "testng", "truth-prebuilt", + "BackupEncryptionRoboTests", ], static_libs: [ "androidx.test.core", diff --git a/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java index 8ec68fdf822d..a432d91828cf 100644 --- a/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java +++ b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java @@ -19,21 +19,35 @@ package com.android.server.backup.encryption; import static com.google.common.truth.Truth.assertThat; import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.security.keystore.recovery.InternalRecoveryServiceException; +import android.security.keystore.recovery.RecoveryController; import androidx.test.core.app.ApplicationProvider; import com.android.server.backup.encryption.client.CryptoBackupServer; +import com.android.server.backup.encryption.keys.KeyWrapUtils; import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager; import com.android.server.backup.encryption.keys.TertiaryKeyManager; import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler; import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; import com.android.server.backup.encryption.tasks.EncryptedFullBackupTask; import com.android.server.backup.encryption.tasks.EncryptedFullRestoreTask; +import com.android.server.backup.encryption.tasks.EncryptedKvBackupTask; +import com.android.server.backup.encryption.tasks.EncryptedKvRestoreTask; +import com.android.server.testing.shadows.DataEntity; +import com.android.server.testing.shadows.ShadowBackupDataInput; +import com.android.server.testing.shadows.ShadowBackupDataOutput; +import com.android.server.testing.shadows.ShadowRecoveryController; 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.annotation.Config; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,15 +56,29 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.Optional; import java.util.Map; +import java.util.Set; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; +@Config( + shadows = { + ShadowBackupDataInput.class, + ShadowBackupDataOutput.class, + ShadowRecoveryController.class + }) @RunWith(RobolectricTestRunner.class) public class RoundTripTest { + private static final DataEntity[] KEY_VALUE_DATA = { + new DataEntity("test_key_1", "test_value_1"), + new DataEntity("test_key_2", "test_value_2"), + new DataEntity("test_key_3", "test_value_3") + }; + /** Amount of data we want to round trip in this test */ private static final int TEST_DATA_SIZE = 1024 * 1024; // 1MB @@ -59,6 +87,7 @@ public class RoundTripTest { /** Key parameters used for the secondary encryption key */ private static final String KEY_ALGORITHM = "AES"; + private static final int KEY_SIZE_BITS = 256; /** Package name for our test package */ @@ -77,25 +106,82 @@ public class RoundTripTest { private RecoverableKeyStoreSecondaryKey mSecondaryKey; /** Source of random material which is considered non-predictable in its' generation */ - private SecureRandom mSecureRandom = new SecureRandom(); + private final SecureRandom mSecureRandom = new SecureRandom(); + + private RecoverableKeyStoreSecondaryKeyManager.RecoverableKeyStoreSecondaryKeyManagerProvider + mSecondaryKeyManagerProvider; + private DummyServer mDummyServer; + private RecoveryController mRecoveryController; + + @Mock private ParcelFileDescriptor mParcelFileDescriptor; @Before - public void setUp() throws NoSuchAlgorithmException { + public void setUp() throws NoSuchAlgorithmException, InternalRecoveryServiceException { + MockitoAnnotations.initMocks(this); + + ShadowBackupDataInput.reset(); + ShadowBackupDataOutput.reset(); + mContext = ApplicationProvider.getApplicationContext(); mSecondaryKey = new RecoverableKeyStoreSecondaryKey(TEST_KEY_ALIAS, generateAesKey()); + mDummyServer = new DummyServer(); + mSecondaryKeyManagerProvider = + () -> + new RecoverableKeyStoreSecondaryKeyManager( + RecoveryController.getInstance(mContext), mSecureRandom); + fillBuffer(mOriginalData); } @Test - public void testRoundTrip() throws Exception { - byte[] backupData = performBackup(mOriginalData); + public void testFull_nonIncrementalBackupAndRestoreAreSuccessful() throws Exception { + byte[] backupData = performFullBackup(mOriginalData); assertThat(backupData).isNotEqualTo(mOriginalData); - byte[] restoredData = performRestore(backupData); + byte[] restoredData = performFullRestore(backupData); assertThat(restoredData).isEqualTo(mOriginalData); } - /** Perform a backup and return the backed-up representation of the data */ - private byte[] performBackup(byte[] backupData) throws Exception { + @Test + public void testKeyValue_nonIncrementalBackupAndRestoreAreSuccessful() throws Exception { + byte[] backupData = performNonIncrementalKeyValueBackup(KEY_VALUE_DATA); + + // Get the secondary key used to do backup. + Optional<RecoverableKeyStoreSecondaryKey> secondaryKey = + mSecondaryKeyManagerProvider.get().get(mDummyServer.mSecondaryKeyAlias); + assertThat(secondaryKey.isPresent()).isTrue(); + + Set<DataEntity> restoredData = performKeyValueRestore(backupData, secondaryKey.get()); + + assertThat(restoredData).containsExactly(KEY_VALUE_DATA).inOrder(); + } + + /** Perform a key/value backup and return the backed-up representation of the data */ + private byte[] performNonIncrementalKeyValueBackup(DataEntity[] backupData) + throws Exception { + // Populate test key/value data. + for (DataEntity entity : backupData) { + ShadowBackupDataInput.addEntity(entity); + } + + EncryptedKvBackupTask.EncryptedKvBackupTaskFactory backupTaskFactory = + new EncryptedKvBackupTask.EncryptedKvBackupTaskFactory(); + EncryptedKvBackupTask backupTask = + backupTaskFactory.newInstance( + mContext, + mSecureRandom, + mDummyServer, + CryptoSettings.getInstance(mContext), + mSecondaryKeyManagerProvider, + mParcelFileDescriptor, + TEST_PACKAGE_NAME); + + backupTask.performBackup(/* incremental */ false); + + return mDummyServer.mStoredData; + } + + /** Perform a full backup and return the backed-up representation of the data */ + private byte[] performFullBackup(byte[] backupData) throws Exception { DummyServer dummyServer = new DummyServer(); EncryptedFullBackupTask backupTask = EncryptedFullBackupTask.newInstance( @@ -109,8 +195,24 @@ public class RoundTripTest { return dummyServer.mStoredData; } - /** Perform a restore and resturn the bytes obtained from the restore process */ - private byte[] performRestore(byte[] backupData) + private Set<DataEntity> performKeyValueRestore( + byte[] backupData, RecoverableKeyStoreSecondaryKey secondaryKey) throws Exception { + EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory restoreTaskFactory = + new EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory(); + EncryptedKvRestoreTask restoreTask = + restoreTaskFactory.newInstance( + mContext, + mSecondaryKeyManagerProvider, + new FakeFullRestoreDownloader(backupData), + secondaryKey.getAlias(), + KeyWrapUtils.wrap( + secondaryKey.getSecretKey(), getTertiaryKey(secondaryKey))); + restoreTask.getRestoreData(mParcelFileDescriptor); + return ShadowBackupDataOutput.getEntities(); + } + + /** Perform a full restore and return the bytes obtained from the restore process */ + private byte[] performFullRestore(byte[] backupData) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException { @@ -118,7 +220,9 @@ public class RoundTripTest { EncryptedFullRestoreTask restoreTask = EncryptedFullRestoreTask.newInstance( - mContext, new FakeFullRestoreDownloader(backupData), getTertiaryKey()); + mContext, + new FakeFullRestoreDownloader(backupData), + getTertiaryKey(mSecondaryKey)); byte[] buffer = new byte[READ_BUFFER_SIZE]; int bytesRead = restoreTask.readNextChunk(buffer); @@ -131,7 +235,7 @@ public class RoundTripTest { } /** Get the tertiary key for our test package from the key manager */ - private SecretKey getTertiaryKey() + private SecretKey getTertiaryKey(RecoverableKeyStoreSecondaryKey secondaryKey) throws IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, NoSuchPaddingException, InvalidKeyException { @@ -140,7 +244,7 @@ public class RoundTripTest { mContext, mSecureRandom, TertiaryKeyRotationScheduler.getInstance(mContext), - mSecondaryKey, + secondaryKey, TEST_PACKAGE_NAME); return tertiaryKeyManager.getKey(); } @@ -162,13 +266,13 @@ public class RoundTripTest { } /** - * Dummy backup data endpoint. This stores the data so we can use it - * in subsequent test steps. + * Dummy backup data endpoint. This stores the data so we can use it in subsequent test steps. */ private static class DummyServer implements CryptoBackupServer { private static final String DUMMY_DOC_ID = "DummyDoc"; byte[] mStoredData = null; + String mSecondaryKeyAlias; @Override public String uploadIncrementalBackup( @@ -190,7 +294,7 @@ public class RoundTripTest { @Override public void setActiveSecondaryKeyAlias( String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) { - throw new RuntimeException("Not Implemented"); + mSecondaryKeyAlias = keyAlias; } } diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java new file mode 100644 index 000000000000..fa4fef50ac1a --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java @@ -0,0 +1,356 @@ +/* + * 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.backup.encryption.tasks; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertThrows; + +import android.app.Application; +import android.util.Pair; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.server.backup.encryption.chunk.ChunkHash; +import com.android.server.backup.encryption.chunking.ProtoStore; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey; +import com.android.server.backup.encryption.keys.TertiaryKeyManager; +import com.android.server.backup.encryption.kv.KeyValueListingBuilder; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.KeyValueListingProto; +import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; +import com.android.server.backup.testing.CryptoTestUtils; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import javax.crypto.SecretKey; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class EncryptedKvBackupTaskTest { + private static final boolean INCREMENTAL = true; + private static final boolean NON_INCREMENTAL = false; + + private static final String TEST_PACKAGE_1 = "com.example.app1"; + private static final String TEST_KEY_1 = "key_1"; + private static final String TEST_KEY_2 = "key_2"; + private static final ChunkHash TEST_HASH_1 = + new ChunkHash(Arrays.copyOf(new byte[] {1}, ChunkHash.HASH_LENGTH_BYTES)); + private static final ChunkHash TEST_HASH_2 = + new ChunkHash(Arrays.copyOf(new byte[] {2}, ChunkHash.HASH_LENGTH_BYTES)); + private static final int TEST_LENGTH_1 = 200; + private static final int TEST_LENGTH_2 = 300; + + @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + + @Captor private ArgumentCaptor<ChunksMetadataProto.ChunkListing> mChunkListingCaptor; + + @Mock private TertiaryKeyManager mTertiaryKeyManager; + @Mock private RecoverableKeyStoreSecondaryKey mSecondaryKey; + @Mock private ProtoStore<KeyValueListingProto.KeyValueListing> mKeyValueListingStore; + @Mock private ProtoStore<ChunksMetadataProto.ChunkListing> mChunkListingStore; + @Mock private KvBackupEncrypter mKvBackupEncrypter; + @Mock private EncryptedBackupTask mEncryptedBackupTask; + @Mock private SecretKey mTertiaryKey; + + private WrappedKeyProto.WrappedKey mWrappedTertiaryKey; + private KeyValueListingProto.KeyValueListing mNewKeyValueListing; + private ChunksMetadataProto.ChunkListing mNewChunkListing; + private EncryptedKvBackupTask mTask; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + Application application = ApplicationProvider.getApplicationContext(); + mKeyValueListingStore = ProtoStore.createKeyValueListingStore(application); + mChunkListingStore = ProtoStore.createChunkListingStore(application); + + mWrappedTertiaryKey = new WrappedKeyProto.WrappedKey(); + + when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(false); + when(mTertiaryKeyManager.getKey()).thenReturn(mTertiaryKey); + when(mTertiaryKeyManager.getWrappedKey()).thenReturn(mWrappedTertiaryKey); + + mNewKeyValueListing = + createKeyValueListing( + CryptoTestUtils.mapOf( + new Pair<>(TEST_KEY_1, TEST_HASH_1), + new Pair<>(TEST_KEY_2, TEST_HASH_2))); + mNewChunkListing = + createChunkListing( + CryptoTestUtils.mapOf( + new Pair<>(TEST_HASH_1, TEST_LENGTH_1), + new Pair<>(TEST_HASH_2, TEST_LENGTH_2))); + when(mKvBackupEncrypter.getNewKeyValueListing()).thenReturn(mNewKeyValueListing); + when(mEncryptedBackupTask.performIncrementalBackup( + eq(mTertiaryKey), eq(mWrappedTertiaryKey), any())) + .thenReturn(mNewChunkListing); + when(mEncryptedBackupTask.performNonIncrementalBackup( + eq(mTertiaryKey), eq(mWrappedTertiaryKey), any())) + .thenReturn(mNewChunkListing); + + mTask = + new EncryptedKvBackupTask( + mTertiaryKeyManager, + mKeyValueListingStore, + mSecondaryKey, + mChunkListingStore, + mKvBackupEncrypter, + mEncryptedBackupTask, + TEST_PACKAGE_1); + } + + @Test + public void testPerformBackup_rotationRequired_deletesListings() throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true); + // Throw an IOException so it aborts before saving the new listings. + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenThrow(IOException.class); + + assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL)); + + assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + } + + @Test + public void testPerformBackup_rotationRequiredButIncremental_throws() throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true); + + assertThrows(NonIncrementalBackupRequiredException.class, + () -> mTask.performBackup(INCREMENTAL)); + } + + @Test + public void testPerformBackup_rotationRequiredAndNonIncremental_performsNonIncrementalBackup() + throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true); + + mTask.performBackup(NON_INCREMENTAL); + + verify(mEncryptedBackupTask) + .performNonIncrementalBackup(eq(mTertiaryKey), eq(mWrappedTertiaryKey), any()); + } + + @Test + public void testPerformBackup_existingStateButNonIncremental_deletesListings() throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + // Throw an IOException so it aborts before saving the new listings. + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenThrow(IOException.class); + + assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL)); + + assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + } + + @Test + public void testPerformBackup_keyValueListingMissing_deletesChunkListingAndPerformsNonIncremental() + throws Exception { + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + // Throw an IOException so it aborts before saving the new listings. + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenThrow(IOException.class); + + assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL)); + + verify(mEncryptedBackupTask).performNonIncrementalBackup(any(), any(), any()); + assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + } + + @Test + public void testPerformBackup_chunkListingMissing_deletesKeyValueListingAndPerformsNonIncremental() + throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + + // Throw an IOException so it aborts before saving the new listings. + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenThrow(IOException.class); + + assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL)); + + verify(mEncryptedBackupTask).performNonIncrementalBackup(any(), any(), any()); + assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent()); + } + + @Test + public void testPerformBackup_existingStateAndIncremental_performsIncrementalBackup() + throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + ChunksMetadataProto.ChunkListing oldChunkListing = + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))); + mChunkListingStore.saveProto(TEST_PACKAGE_1, oldChunkListing); + + mTask.performBackup(INCREMENTAL); + + verify(mEncryptedBackupTask) + .performIncrementalBackup( + eq(mTertiaryKey), eq(mWrappedTertiaryKey), mChunkListingCaptor.capture()); + assertChunkListingsEqual(mChunkListingCaptor.getValue(), oldChunkListing); + } + + @Test + public void testPerformBackup_noExistingStateAndNonIncremental_performsNonIncrementalBackup() + throws Exception { + mTask.performBackup(NON_INCREMENTAL); + + verify(mEncryptedBackupTask) + .performNonIncrementalBackup(eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(null)); + } + + @Test + public void testPerformBackup_incremental_savesNewListings() throws Exception { + mKeyValueListingStore.saveProto( + TEST_PACKAGE_1, + createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1)))); + mChunkListingStore.saveProto( + TEST_PACKAGE_1, + createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)))); + + mTask.performBackup(INCREMENTAL); + + KeyValueListingProto.KeyValueListing actualKeyValueListing = + mKeyValueListingStore.loadProto(TEST_PACKAGE_1).get(); + ChunksMetadataProto.ChunkListing actualChunkListing = + mChunkListingStore.loadProto(TEST_PACKAGE_1).get(); + assertKeyValueListingsEqual(actualKeyValueListing, mNewKeyValueListing); + assertChunkListingsEqual(actualChunkListing, mNewChunkListing); + } + + @Test + public void testPerformBackup_nonIncremental_savesNewListings() throws Exception { + mTask.performBackup(NON_INCREMENTAL); + + KeyValueListingProto.KeyValueListing actualKeyValueListing = + mKeyValueListingStore.loadProto(TEST_PACKAGE_1).get(); + ChunksMetadataProto.ChunkListing actualChunkListing = + mChunkListingStore.loadProto(TEST_PACKAGE_1).get(); + assertKeyValueListingsEqual(actualKeyValueListing, mNewKeyValueListing); + assertChunkListingsEqual(actualChunkListing, mNewChunkListing); + } + + private static KeyValueListingProto.KeyValueListing createKeyValueListing( + Map<String, ChunkHash> pairs) { + return new KeyValueListingBuilder().addAll(pairs).build(); + } + + private static ChunksMetadataProto.ChunkListing createChunkListing( + Map<ChunkHash, Integer> chunks) { + ChunksMetadataProto.Chunk[] listingChunks = new ChunksMetadataProto.Chunk[chunks.size()]; + int chunksAdded = 0; + for (Entry<ChunkHash, Integer> entry : chunks.entrySet()) { + listingChunks[chunksAdded] = CryptoTestUtils.newChunk(entry.getKey(), entry.getValue()); + chunksAdded++; + } + return CryptoTestUtils.newChunkListingWithoutDocId( + /* fingerprintSalt */ new byte[0], + ChunksMetadataProto.AES_256_GCM, + ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED, + listingChunks); + } + + private static void assertKeyValueListingsEqual( + KeyValueListingProto.KeyValueListing actual, + KeyValueListingProto.KeyValueListing expected) { + KeyValueListingProto.KeyValueEntry[] actualEntries = actual.entries; + KeyValueListingProto.KeyValueEntry[] expectedEntries = expected.entries; + assertThat(actualEntries.length).isEqualTo(expectedEntries.length); + for (int i = 0; i < actualEntries.length; i++) { + assertWithMessage("entry " + i) + .that(actualEntries[i].key) + .isEqualTo(expectedEntries[i].key); + assertWithMessage("entry " + i) + .that(actualEntries[i].hash) + .isEqualTo(expectedEntries[i].hash); + } + } + + private static void assertChunkListingsEqual( + ChunksMetadataProto.ChunkListing actual, ChunksMetadataProto.ChunkListing expected) { + ChunksMetadataProto.Chunk[] actualChunks = actual.chunks; + ChunksMetadataProto.Chunk[] expectedChunks = expected.chunks; + assertThat(actualChunks.length).isEqualTo(expectedChunks.length); + for (int i = 0; i < actualChunks.length; i++) { + assertWithMessage("chunk " + i) + .that(actualChunks[i].hash) + .isEqualTo(expectedChunks[i].hash); + assertWithMessage("chunk " + i) + .that(actualChunks[i].length) + .isEqualTo(expectedChunks[i].length); + } + assertThat(actual.cipherType).isEqualTo(expected.cipherType); + assertThat(actual.documentId) + .isEqualTo(expected.documentId == null ? "" : expected.documentId); + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java new file mode 100644 index 000000000000..6666d95d9a2d --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java @@ -0,0 +1,185 @@ +/* + * 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.backup.encryption.tasks; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.os.ParcelFileDescriptor; + +import com.android.server.backup.encryption.chunk.ChunkHash; +import com.android.server.backup.encryption.chunking.ChunkHasher; +import com.android.server.backup.testing.CryptoTestUtils; +import com.android.server.testing.shadows.DataEntity; +import com.android.server.testing.shadows.ShadowBackupDataOutput; + +import com.google.protobuf.nano.MessageNano; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@Config(shadows = {ShadowBackupDataOutput.class}) +@RunWith(RobolectricTestRunner.class) +public class EncryptedKvRestoreTaskTest { + private static final String TEST_KEY_1 = "test_key_1"; + private static final String TEST_KEY_2 = "test_key_2"; + private static final String TEST_KEY_3 = "test_key_3"; + private static final byte[] TEST_VALUE_1 = {1, 2, 3}; + private static final byte[] TEST_VALUE_2 = {4, 5, 6}; + private static final byte[] TEST_VALUE_3 = {20, 25, 30, 35}; + + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private File temporaryDirectory; + + @Mock private ParcelFileDescriptor mParcelFileDescriptor; + @Mock private ChunkHasher mChunkHasher; + @Mock private FullRestoreToFileTask mFullRestoreToFileTask; + @Mock private BackupFileDecryptorTask mBackupFileDecryptorTask; + + private EncryptedKvRestoreTask task; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mChunkHasher.computeHash(any())) + .thenAnswer(invocation -> fakeHash(invocation.getArgument(0))); + doAnswer(invocation -> writeTestPairsToFile(invocation.getArgument(0))) + .when(mFullRestoreToFileTask) + .restoreToFile(any()); + doAnswer( + invocation -> + readPairsFromFile( + invocation.getArgument(0), invocation.getArgument(1))) + .when(mBackupFileDecryptorTask) + .decryptFile(any(), any()); + + temporaryDirectory = temporaryFolder.newFolder(); + task = + new EncryptedKvRestoreTask( + temporaryDirectory, + mChunkHasher, + mFullRestoreToFileTask, + mBackupFileDecryptorTask); + } + + @Test + public void testGetRestoreData_writesPairsToOutputInOrder() throws Exception { + task.getRestoreData(mParcelFileDescriptor); + + assertThat(ShadowBackupDataOutput.getEntities()) + .containsExactly( + new DataEntity(TEST_KEY_1, TEST_VALUE_1), + new DataEntity(TEST_KEY_2, TEST_VALUE_2), + new DataEntity(TEST_KEY_3, TEST_VALUE_3)) + .inOrder(); + } + + @Test + public void testGetRestoreData_exceptionDuringDecryption_throws() throws Exception { + doThrow(IOException.class).when(mBackupFileDecryptorTask).decryptFile(any(), any()); + assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor)); + } + + @Test + public void testGetRestoreData_exceptionDuringDownload_throws() throws Exception { + doThrow(IOException.class).when(mFullRestoreToFileTask).restoreToFile(any()); + assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor)); + } + + @Test + public void testGetRestoreData_exceptionDuringDecryption_deletesTemporaryFiles() throws Exception { + doThrow(InvalidKeyException.class).when(mBackupFileDecryptorTask).decryptFile(any(), any()); + assertThrows(InvalidKeyException.class, () -> task.getRestoreData(mParcelFileDescriptor)); + assertThat(temporaryDirectory.listFiles()).isEmpty(); + } + + @Test + public void testGetRestoreData_exceptionDuringDownload_deletesTemporaryFiles() throws Exception { + doThrow(IOException.class).when(mFullRestoreToFileTask).restoreToFile(any()); + assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor)); + assertThat(temporaryDirectory.listFiles()).isEmpty(); + } + + private static Void writeTestPairsToFile(File file) throws IOException { + // Write the pairs out of order to check the task sorts them. + Set<byte[]> pairs = + new HashSet<>( + Arrays.asList( + createPair(TEST_KEY_1, TEST_VALUE_1), + createPair(TEST_KEY_3, TEST_VALUE_3), + createPair(TEST_KEY_2, TEST_VALUE_2))); + + try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) { + oos.writeObject(pairs); + } + return null; + } + + private static Void readPairsFromFile(File file, DecryptedChunkOutput decryptedChunkOutput) + throws IOException, ClassNotFoundException, InvalidKeyException, + NoSuchAlgorithmException { + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); + DecryptedChunkOutput output = decryptedChunkOutput.open()) { + Set<byte[]> pairs = readPairs(ois); + for (byte[] pair : pairs) { + output.processChunk(pair, pair.length); + } + } + + return null; + } + + private static byte[] createPair(String key, byte[] value) { + return MessageNano.toByteArray(CryptoTestUtils.newPair(key, value)); + } + + @SuppressWarnings("unchecked") // deserialization. + private static Set<byte[]> readPairs(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + return (Set<byte[]>) ois.readObject(); + } + + private static ChunkHash fakeHash(byte[] data) { + return new ChunkHash(Arrays.copyOf(data, ChunkHash.HASH_LENGTH_BYTES)); + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java index 5dfd5ee8ad53..b0c02ba637e0 100644 --- a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java @@ -16,6 +16,8 @@ package com.android.server.backup.testing; +import android.util.Pair; + import com.android.server.backup.encryption.chunk.ChunkHash; import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; import com.android.server.backup.encryption.protos.nano.KeyValuePairProto; @@ -23,6 +25,8 @@ import com.android.server.backup.encryption.protos.nano.KeyValuePairProto; import java.nio.charset.Charset; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Random; import javax.crypto.KeyGenerator; @@ -162,4 +166,12 @@ public class CryptoTestUtils { clone.checksum = Arrays.copyOf(original.checksum, original.checksum.length); return clone; } + + public static <K, V> Map<K, V> mapOf(Pair<K, V>... pairs) { + Map<K, V> map = new HashMap<>(); + for (Pair<K, V> pair : pairs) { + map.put(pair.first, pair.second); + } + return map; + } } diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java new file mode 100644 index 000000000000..2302e555fb44 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java @@ -0,0 +1,66 @@ +/* + * 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.testing.shadows; + +import android.app.backup.BackupDataOutput; + +import java.io.FileDescriptor; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Assert; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** Shadow for BackupDataOutput. */ +@Implements(BackupDataOutput.class) +public class ShadowBackupDataOutput { + private static final List<DataEntity> ENTRIES = new ArrayList<>(); + + private String mCurrentKey; + private int mDataSize; + + public static void reset() { + ENTRIES.clear(); + } + + public static Set<DataEntity> getEntities() { + return new LinkedHashSet<>(ENTRIES); + } + + public void __constructor__(FileDescriptor fd) {} + + public void __constructor__(FileDescriptor fd, long quota) {} + + public void __constructor__(FileDescriptor fd, long quota, int transportFlags) {} + + @Implementation + public int writeEntityHeader(String key, int size) { + mCurrentKey = key; + mDataSize = size; + return 0; + } + + @Implementation + public int writeEntityData(byte[] data, int size) { + Assert.assertEquals("ShadowBackupDataOutput expects size = mDataSize", size, mDataSize); + ENTRIES.add(new DataEntity(mCurrentKey, data, mDataSize)); + return 0; + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 9a063aa7b791..5ec1baee5b14 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -29,6 +29,7 @@ import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationData; @@ -42,6 +43,8 @@ import javax.inject.Singleton; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; @Module abstract class CarSystemUIModule { @@ -94,4 +97,9 @@ abstract class CarSystemUIModule { @Binds abstract SystemUIRootComponent bindSystemUIRootComponent( CarSystemUIRootComponent systemUIRootComponent); + + @Binds + @IntoMap + @ClassKey(StatusBar.class) + public abstract SystemUI providesStatusBar(CarStatusBar statusBar); } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index b0ab5b49f340..d21f09ce160a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.car; +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -34,6 +36,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.os.IBinder; +import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.GestureDetector; @@ -57,36 +60,83 @@ import com.android.car.notification.NotificationClickHandlerFactory; import com.android.car.notification.NotificationDataManager; import com.android.car.notification.NotificationViewController; import com.android.car.notification.PreprocessingManager; +import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.BatteryMeterView; import com.android.systemui.CarSystemUIFactory; import com.android.systemui.Dependency; +import com.android.systemui.ForegroundServiceController; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; +import com.android.systemui.UiOffloadThread; +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingLog; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.NotificationAlertingManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Map; +import javax.inject.Inject; +import javax.inject.Named; + /** * A status bar (and navigation bar) tailored for the automotive use case. */ @@ -175,6 +225,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private boolean mHideNavBarForKeyboard; private boolean mBottomNavBarVisible; + private final NavigationBarController mNavigationBarController; + private final CarPowerStateListener mCarPowerStateListener = (int state) -> { // When the car powers on, clear all notifications and mute/unread states. @@ -189,6 +241,116 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }; + @Inject + public CarStatusBar( + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + InjectionInflationController injectionInflationController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + NotifPipelineInitializer notifPipelineInitializer, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController) { + super( + lightBarController, + autoHideController, + keyguardUpdateMonitor, + statusBarIconController, + dozeLog, + injectionInflationController, + pulseExpansionHandler, + notificationWakeUpCoordinator, + keyguardBypassController, + keyguardStateController, + headsUpManagerPhone, + dynamicPrivacyController, + bypassHeadsUpNotifier, + allowNotificationLongPress, + notifPipelineInitializer, + falsingManager, + broadcastDispatcher, + remoteInputQuickSettingsDisabler, + notificationGutsManager, + notificationLogger, + notificationEntryManager, + notificationInterruptionStateProvider, + notificationViewHierarchyManager, + foregroundServiceController, + appOpsController, + keyguardViewMediator, + zenModeController, + notificationAlertingManager, + displayMetrics, + metricsLogger, + uiOffloadThread, + notificationMediaManager, + lockScreenUserManager, + remoteInputManager, + userSwitcherController, + networkController, + batteryController, + colorExtractor, + screenLifecycle, + wakefulnessLifecycle, + statusBarStateController, + vibratorHelper, + bubbleController, + groupManager, + groupAlertTransferHelper, + visualStabilityManager, + deviceProvisionedController, + navigationBarController, + assistManager, + notificationListener, + configurationController, + statusBarWindowController); + mNavigationBarController = navigationBarController; + } + @Override public void start() { // get the provisioned state before calling the parent class since it's that flow that diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index 827a59eddf56..743ab4737bfb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -23,13 +23,17 @@ import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.car.userlib.CarUserManagerHelper; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.AsyncTask; +import android.os.UserHandle; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -53,13 +57,19 @@ import java.util.List; * Displays a GridLayout with icons for the users in the system to allow switching between users. * One of the uses of this is for the lock screen in auto. */ -public class UserGridRecyclerView extends RecyclerView implements - CarUserManagerHelper.OnUsersUpdateListener { +public class UserGridRecyclerView extends RecyclerView { private UserSelectionListener mUserSelectionListener; private UserAdapter mAdapter; private CarUserManagerHelper mCarUserManagerHelper; private Context mContext; + private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUsersUpdate(); + } + }; + public UserGridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; @@ -75,7 +85,7 @@ public class UserGridRecyclerView extends RecyclerView implements @Override public void onFinishInflate() { super.onFinishInflate(); - mCarUserManagerHelper.registerOnUsersUpdateListener(this); + registerForUserEvents(); } /** @@ -84,7 +94,7 @@ public class UserGridRecyclerView extends RecyclerView implements @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - mCarUserManagerHelper.unregisterOnUsersUpdateListener(this); + unregisterForUserEvents(); } /** @@ -161,13 +171,32 @@ public class UserGridRecyclerView extends RecyclerView implements mUserSelectionListener = userSelectionListener; } - @Override - public void onUsersUpdate() { + private void onUsersUpdate() { mAdapter.clearUsers(); mAdapter.updateUsers(createUserRecords(mCarUserManagerHelper.getAllUsers())); mAdapter.notifyDataSetChanged(); } + private void registerForUserEvents() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_ADDED); + filter.addAction(Intent.ACTION_USER_INFO_CHANGED); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_USER_STOPPED); + filter.addAction(Intent.ACTION_USER_UNLOCKED); + mContext.registerReceiverAsUser( + mUserUpdateReceiver, + UserHandle.ALL, + filter, + /* broadcastPermission= */ null, + /* scheduler= */ null); + } + + private void unregisterForUserEvents() { + mContext.unregisterReceiver(mUserUpdateReceiver); + } + /** * Adapter to populate the grid layout with the available user profiles */ diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index a8ce196cc359..a3d420ee4cdf 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -104,12 +104,6 @@ it should be shown. Shows the drag handle for the divider between two apps when in split screen mode. -### [com.android.systemui.SystemBars](/packages/SystemUI/src/com/android/systemui/SystemBars.java) - -This is a proxy to the actual SystemUI for the status bar. This loads from -config_statusBarComponent which defaults to StatusBar. (maybe this should be -removed and copy how config_systemUiVendorServiceComponent works) - ### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java) This shows the UI for the status bar and the notification shade it contains. diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 61210d3e0011..105b27eb7e1b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -279,7 +279,7 @@ <item>com.android.systemui.recents.Recents</item> <item>com.android.systemui.volume.VolumeUI</item> <item>com.android.systemui.stackdivider.Divider</item> - <item>com.android.systemui.SystemBars</item> + <item>com.android.systemui.statusbar.phone.StatusBar</item> <item>com.android.systemui.usb.StorageNotification</item> <item>com.android.systemui.power.PowerUI</item> <item>com.android.systemui.media.RingtonePlayer</item> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 97e2f0f6562b..c5547800360d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -118,10 +118,13 @@ <string name="status_bar_use_physical_keyboard">Physical keyboard</string> <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] --> - <string name="usb_device_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_device">%2$s</xliff:g>?</string> + <string name="usb_device_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?</string> + + <!-- Checkbox label for USB device dialogs with warning text for USB device dialogs. [CHAR LIMIT=200]--> + <string name="usb_device_permission_prompt_warn">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device.</string> <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] --> - <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_accessory">%2$s</xliff:g>?</string> + <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_accessory" example="USB Dock">%2$s</xliff:g>?</string> <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] --> <string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string> @@ -860,6 +863,8 @@ <string name="quick_settings_notifications_label">Notifications</string> <!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] --> <string name="quick_settings_flashlight_label">Flashlight</string> + <!-- QuickSettings: Flashlight, used when it's not available due to camera in use [CHAR LIMIT=NONE] --> + <string name="quick_settings_flashlight_camera_in_use">Camera in use</string> <!-- QuickSettings: Cellular detail panel title [CHAR LIMIT=NONE] --> <string name="quick_settings_cellular_detail_title">Mobile data</string> <!-- QuickSettings: Cellular detail panel, data usage title [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index e1b723e4d443..a97ec6442e14 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -57,6 +57,7 @@ public class CarrierTextController { private static final String TAG = "CarrierTextController"; private final boolean mIsEmergencyCallCapable; + private final Handler mMainHandler; private boolean mTelephonyCapable; private boolean mShowMissingSim; private boolean mShowAirplaneMode; @@ -167,8 +168,9 @@ public class CarrierTextController { mSeparator = separator; mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); mSimSlotsNumber = ((TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE)).getPhoneCount(); + Context.TELEPHONY_SERVICE)).getMaxPhoneCount(); mSimErrorState = new boolean[mSimSlotsNumber]; + mMainHandler = Dependency.get(Dependency.MAIN_HANDLER); } /** @@ -227,7 +229,12 @@ public class CarrierTextController { if (whitelistIpcs(() -> ConnectivityManager.from(mContext).isNetworkSupported( ConnectivityManager.TYPE_MOBILE))) { mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mKeyguardUpdateMonitor.registerCallback(mCallback); + // Keyguard update monitor expects callbacks from main thread + mMainHandler.post(() -> { + if (mKeyguardUpdateMonitor != null) { + mKeyguardUpdateMonitor.registerCallback(mCallback); + } + }); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); telephonyManager.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); @@ -239,7 +246,12 @@ public class CarrierTextController { } else { mCarrierTextCallback = null; if (mKeyguardUpdateMonitor != null) { - mKeyguardUpdateMonitor.removeCallback(mCallback); + // Keyguard update monitor expects callbacks from main thread + mMainHandler.post(() -> { + if (mKeyguardUpdateMonitor != null) { + mKeyguardUpdateMonitor.removeCallback(mCallback); + } + }); mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); } telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); @@ -364,10 +376,9 @@ public class CarrierTextController { @VisibleForTesting protected void postToCallback(CarrierTextCallbackInfo info) { - Handler handler = Dependency.get(Dependency.MAIN_HANDLER); final CarrierTextCallback callback = mCarrierTextCallback; if (callback != null) { - handler.post(() -> callback.updateCarrierInfo(info)); + mMainHandler.post(() -> callback.updateCarrierInfo(info)); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 8d167e8783bf..a00a8e7aa4e9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -128,7 +128,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mSecurityModel = new KeyguardSecurityModel(context); + mSecurityModel = Dependency.get(KeyguardSecurityModel.class); mLockPatternUtils = new LockPatternUtils(context); mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index bb89959b7a11..1395fd9e3482 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -25,6 +25,10 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton public class KeyguardSecurityModel { /** @@ -46,6 +50,7 @@ public class KeyguardSecurityModel { private LockPatternUtils mLockPatternUtils; + @Inject KeyguardSecurityModel(Context context) { mContext = context; mLockPatternUtils = new LockPatternUtils(context); @@ -57,7 +62,7 @@ public class KeyguardSecurityModel { mLockPatternUtils = utils; } - SecurityMode getSecurityMode(int userId) { + public SecurityMode getSecurityMode(int userId) { KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a6b3be23417e..dc8ee16e8645 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -58,6 +58,7 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; @@ -329,6 +330,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray(); private SparseBooleanArray mUserHasTrust = new SparseBooleanArray(); private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray(); + private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray(); private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray(); private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray(); private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray(); @@ -472,6 +474,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { public void onTrustManagedChanged(boolean managed, int userId) { checkIsHandlerThread(); mUserTrustIsManaged.put(userId, managed); + mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -925,6 +928,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId); } + /** + * Cached version of {@link TrustManager#isTrustUsuallyManaged(int)}. + */ + public boolean isTrustUsuallyManaged(int userId) { + checkIsHandlerThread(); + return mUserTrustIsUsuallyManaged.get(userId); + } + public boolean isUnlockingWithBiometricAllowed() { return mStrongAuthTracker.isUnlockingWithBiometricAllowed(); } @@ -1474,9 +1485,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mUserIsUnlocked.put(userId, mUserManager.isUserUnlocked(userId)); } - private void handleUserRemoved(int userId) { + @VisibleForTesting + void handleUserRemoved(int userId) { checkIsHandlerThread(); mUserIsUnlocked.delete(userId); + mUserTrustIsUsuallyManaged.delete(userId); } @VisibleForTesting @@ -1662,7 +1675,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { e.rethrowAsRuntimeException(); } - mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); + mTrustManager = context.getSystemService(TrustManager.class); mTrustManager.registerTrustListener(this); mLockPatternUtils = new LockPatternUtils(context); mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); @@ -1697,6 +1710,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user)); mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled(); + List<UserInfo> allUsers = mUserManager.getUsers(); + for (UserInfo userInfo : allUsers) { + mUserTrustIsUsuallyManaged.put(userInfo.id, + mTrustManager.isTrustUsuallyManaged(userInfo.id)); + } updateAirplaneModeState(); TelephonyManager telephony = @@ -2048,6 +2066,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { */ private void handleUserSwitching(int userId, IRemoteCallback reply) { checkIsHandlerThread(); + mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 37bb54cc1b11..07bfa7194413 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -30,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.Preconditions; +import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.clock.ClockManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -316,6 +317,7 @@ public class Dependency { @Inject Lazy<FalsingManager> mFalsingManager; @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; @Inject Lazy<AlarmManager> mAlarmManager; + @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel; @Inject public Dependency() { @@ -501,6 +503,7 @@ public class Dependency { mProviders.put(FalsingManager.class, mFalsingManager::get); mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); mProviders.put(AlarmManager.class, mAlarmManager::get); + mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java index 818b5e1c69f4..f9f0f1bad2fa 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java @@ -30,6 +30,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSTileHost; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; @@ -199,6 +200,12 @@ public abstract class DependencyBinder { /** */ @Binds + public abstract SysuiStatusBarStateController providesSysuiStatusBarStateController( + StatusBarStateControllerImpl statusBarStateControllerImpl); + + /** + */ + @Binds public abstract StatusBarIconController provideStatusBarIconController( StatusBarIconControllerImpl controllerImpl); diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java index 239cbfe38975..0d24321d8db7 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java @@ -40,6 +40,7 @@ import android.view.WindowManagerGlobal; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.plugins.PluginInitializerImpl; import com.android.systemui.shared.plugins.PluginManager; @@ -238,4 +239,10 @@ public class DependencyProvider { public AlarmManager provideAlarmManager(Context context) { return context.getSystemService(AlarmManager.class); } + + /** */ + @Provides + public LockPatternUtils provideLockPatternUtils(Context context) { + return new LockPatternUtils(context); + } } diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java index 0e079e36a175..5c561e5bf6f2 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java @@ -83,7 +83,9 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx } } }; - mHandler.postDelayed(r, MIN_FGS_TIME_MS); + long delayAmt = MIN_FGS_TIME_MS + - (System.currentTimeMillis() - entry.notification.getPostTime()); + mHandler.postDelayed(r, delayAmt); } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemBars.java b/packages/SystemUI/src/com/android/systemui/SystemBars.java deleted file mode 100644 index c4c0fd6da124..000000000000 --- a/packages/SystemUI/src/com/android/systemui/SystemBars.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui; - -import android.util.Log; - -import com.android.systemui.statusbar.phone.StatusBar; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Ensure a single status bar service implementation is running at all times, using the in-process - * implementation according to the product config. - */ -public class SystemBars extends SystemUI { - private static final String TAG = "SystemBars"; - private static final boolean DEBUG = false; - private static final int WAIT_FOR_BARS_TO_DIE = 500; - - // in-process fallback implementation, per the product config - private SystemUI mStatusBar; - - @Override - public void start() { - if (DEBUG) Log.d(TAG, "start"); - createStatusBarFromConfig(); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mStatusBar != null) { - mStatusBar.dump(fd, pw, args); - } - } - - @Override - public void onBootCompleted() { - if (mStatusBar != null) { - mStatusBar.onBootCompleted(); - } - } - - private void createStatusBarFromConfig() { - if (DEBUG) Log.d(TAG, "createStatusBarFromConfig"); - final String clsName = mContext.getString(R.string.config_statusBarComponent); - if (clsName == null || clsName.length() == 0) { - throw andLog("No status bar component configured", null); - } - Class<?> cls = null; - try { - cls = mContext.getClassLoader().loadClass(clsName); - } catch (Throwable t) { - throw andLog("Error loading status bar component: " + clsName, t); - } - try { - mStatusBar = (SystemUI) cls.newInstance(); - } catch (Throwable t) { - throw andLog("Error creating status bar component: " + clsName, t); - } - mStatusBar.mContext = mContext; - mStatusBar.mComponents = mComponents; - if (mStatusBar instanceof StatusBar) { - SystemUIFactory.getInstance().getRootComponent() - .getStatusBarInjector() - .createStatusBar((StatusBar) mStatusBar); - } - mStatusBar.start(); - if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName()); - } - - private RuntimeException andLog(String msg, Throwable t) { - Log.w(TAG, msg, t); - throw new RuntimeException(msg, t); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java index ba2dec0ff116..785038f2b7f7 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java @@ -44,7 +44,7 @@ public abstract class SystemUIBinder { @ClassKey(PowerUI.class) public abstract SystemUI bindPowerUI(PowerUI sysui); - /** Inject into StatusBar. */ + /** Inject into Recents. */ @Binds @IntoMap @ClassKey(Recents.class) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java index 262b5ec50d83..72831e99e122 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java @@ -40,6 +40,8 @@ import javax.inject.Singleton; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; /** * A dagger module for injecting default implementations of components of System UI that may be @@ -76,6 +78,11 @@ abstract class SystemUIDefaultModule { return SysUiServiceProvider.getComponent(context, StatusBar.class); } + @Binds + @IntoMap + @ClassKey(StatusBar.class) + public abstract SystemUI providesStatusBar(StatusBar statusBar); + @Singleton @Provides @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java index cb7c998fad8e..8105c6a6e940 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java @@ -37,7 +37,7 @@ import java.util.Locale; * adb shell setprop debug.falsing_log true * * The log gets dumped as part of the SystemUI services. To dump on demand: - * adb shell dumpsys activity service com.android.systemui SystemBars | grep -A 999 FALSING | less + * adb shell dumpsys activity service com.android.systemui StatusBar | grep -A 999 FALSING | less * * To dump into logcat: * adb shell setprop debug.falsing_logcat true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d2a9c750bbc6..a8027c025cf2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -100,6 +100,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import javax.inject.Inject; +import javax.inject.Singleton; /** * Mediates requests related to the keyguard. This includes queries about the @@ -142,6 +143,7 @@ import javax.inject.Inject; * directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI * thread of the keyguard. */ +@Singleton public class KeyguardViewMediator extends SystemUI { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; @@ -232,7 +234,7 @@ public class KeyguardViewMediator extends SystemUI { */ private PowerManager.WakeLock mShowKeyguardWakeLock; - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; // these are protected by synchronized (this) @@ -315,7 +317,7 @@ public class KeyguardViewMediator extends SystemUI { * the keyguard. */ private boolean mWaitingUntilKeyguardVisible = false; - private LockPatternUtils mLockPatternUtils; + private final LockPatternUtils mLockPatternUtils; private boolean mKeyguardDonePending = false; private boolean mHideAnimationRun = false; private boolean mHideAnimationRunning = false; @@ -648,29 +650,26 @@ public class KeyguardViewMediator extends SystemUI { @Override public int getBouncerPromptReason() { - // TODO(b/140053364) - return whitelistIpcs(() -> { - int currentUser = ActivityManager.getCurrentUser(); - boolean trust = mTrustManager.isTrustUsuallyManaged(currentUser); - boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser); - boolean any = trust || biometrics; - KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker = - mUpdateMonitor.getStrongAuthTracker(); - int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser); - - if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) { - return KeyguardSecurityView.PROMPT_REASON_RESTART; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) { - return KeyguardSecurityView.PROMPT_REASON_TIMEOUT; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) { - return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; - } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { - return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) { - return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; - } - return KeyguardSecurityView.PROMPT_REASON_NONE; - }); + int currentUser = KeyguardUpdateMonitor.getCurrentUser(); + boolean trust = mUpdateMonitor.isTrustUsuallyManaged(currentUser); + boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser); + boolean any = trust || biometrics; + KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker = + mUpdateMonitor.getStrongAuthTracker(); + int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser); + + if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) { + return KeyguardSecurityView.PROMPT_REASON_RESTART; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) { + return KeyguardSecurityView.PROMPT_REASON_TIMEOUT; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) { + return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; + } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { + return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) { + return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; + } + return KeyguardSecurityView.PROMPT_REASON_NONE; } @Override @@ -682,10 +681,21 @@ public class KeyguardViewMediator extends SystemUI { }; @Inject - public KeyguardViewMediator(FalsingManager falsingManager) { + public KeyguardViewMediator( + Context context, + FalsingManager falsingManager, + LockPatternUtils lockPatternUtils) { super(); + mContext = context; mFalsingManager = falsingManager; + + mLockPatternUtils = lockPatternUtils; + mStatusBarKeyguardViewManager = + SystemUIFactory.getInstance().createStatusBarKeyguardViewManager( + mContext, + mViewMediatorCallback, + mLockPatternUtils); } public void userActivity() { @@ -699,7 +709,7 @@ public class KeyguardViewMediator extends SystemUI { private void setupLocked() { mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); + mTrustManager = mContext.getSystemService(TrustManager.class); mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); mShowKeyguardWakeLock.setReferenceCounted(false); @@ -723,7 +733,6 @@ public class KeyguardViewMediator extends SystemUI { mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mLockPatternUtils = new LockPatternUtils(mContext); KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard @@ -737,9 +746,6 @@ public class KeyguardViewMediator extends SystemUI { setShowingLocked(false /* showing */, true /* forceCallbacks */); } - mStatusBarKeyguardViewManager = - SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext, - mViewMediatorCallback, mLockPatternUtils); final ContentResolver cr = mContext.getContentResolver(); mDeviceInteractive = mPM.isInteractive(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 2755e9880b58..dafdd89ee62c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -101,11 +101,15 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements state.slash = new SlashState(); } state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); + state.secondaryLabel = ""; if (!mFlashlightController.isAvailable()) { state.icon = mIcon; state.slash.isSlashed = true; + state.secondaryLabel = mContext.getString( + R.string.quick_settings_flashlight_camera_in_use); state.contentDescription = mContext.getString( - R.string.accessibility_quick_settings_flashlight_unavailable); + R.string.accessibility_quick_settings_flashlight_unavailable) + + ", " + state.secondaryLabel; state.state = Tile.STATE_UNAVAILABLE; return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index 09f80455a1b0..16cdfaa18a53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -237,6 +237,7 @@ public class NavigationBarController implements Callbacks { /** @return {@link AssistHandleViewController} (only on the default display). */ public AssistHandleViewController getAssistHandlerViewController() { - return getDefaultNavigationBarFragment().getAssistHandlerViewController(); + NavigationBarFragment navBar = getDefaultNavigationBarFragment(); + return navBar == null ? null : navBar.getAssistHandlerViewController(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java index 4700baae8fab..18d436ff7659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java @@ -421,7 +421,7 @@ public class NotificationGuts extends FrameLayout { } /** Listener for animations executed in {@link #animateClose(int, int, boolean)}. */ - private static class AnimateCloseListener extends AnimatorListenerAdapter { + private class AnimateCloseListener extends AnimatorListenerAdapter { final View mView; private final GutsContent mGutsContent; @@ -433,8 +433,10 @@ public class NotificationGuts extends FrameLayout { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mView.setVisibility(View.GONE); - mGutsContent.onFinishedClosing(); + if (!isExposed()) { + mView.setVisibility(View.GONE); + mGutsContent.onFinishedClosing(); + } } } } 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 9d0dd6b683cf..2b7deec87715 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 @@ -100,6 +100,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx protected String mKeyToRemoveOnGutsClosed; private StatusBar mStatusBar; + private Runnable mOpenRunnable; @Inject public NotificationGutsManager( @@ -343,6 +344,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls, int x, int y, boolean resetMenu) { if (mNotificationGutsExposed != null) { + mNotificationGutsExposed.removeCallbacks(mOpenRunnable); mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force); } if (resetMenu) { @@ -445,7 +447,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // ensure that it's laid but not visible until actually laid out guts.setVisibility(View.INVISIBLE); // Post to ensure the the guts are properly laid out. - guts.post(new Runnable() { + mOpenRunnable = new Runnable() { @Override public void run() { if (row.getWindowToken() == null) { @@ -470,7 +472,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mListContainer.onHeightChanged(row, true /* needsAnimation */); mGutsMenuItem = menuItem; } - }); + }; + guts.post(mOpenRunnable); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index c3de84366d4b..f34c15c7099d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone; import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; import android.content.Context; @@ -38,11 +37,13 @@ import android.view.WindowInsets; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; @@ -461,15 +462,9 @@ public class KeyguardBouncer { * notifications on Keyguard, like SIM PIN/PUK. */ public boolean needsFullscreenBouncer() { - // TODO(b/140059518) - return whitelistIpcs(() -> { - ensureView(); - if (mKeyguardView != null) { - SecurityMode mode = mKeyguardView.getSecurityMode(); - return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; - } - return false; - }); + SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode( + KeyguardUpdateMonitor.getCurrentUser()); + return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 3817197ca1b6..5ba19cca6532 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -41,6 +41,7 @@ import com.android.internal.graphics.ColorUtils; import com.android.internal.util.function.TriConsumer; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -311,10 +312,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Docking pulses may take a long time, wallpapers should also fade away after a while. mWallpaperVisibilityTimedOut = false; if (shouldFadeAwayWallpaper()) { - mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(), - AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); + DejankUtils.postAfterTraversal(() -> { + mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(), + AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); + }); } else { - mTimeTicker.cancel(); + DejankUtils.postAfterTraversal(mTimeTicker::cancel); } if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) { @@ -430,8 +433,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // and docking. if (mWallpaperVisibilityTimedOut) { mWallpaperVisibilityTimedOut = false; - mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(), - AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); + DejankUtils.postAfterTraversal(() -> { + mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(), + AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); + }); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 5fc2d9beab89..da5931a50ba8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -347,10 +347,9 @@ public class StatusBar extends SystemUI implements DemoMode, private BrightnessMirrorController mBrightnessMirrorController; private boolean mBrightnessMirrorVisible; protected BiometricUnlockController mBiometricUnlockController; - private LightBarController mLightBarController; + private final LightBarController mLightBarController; protected LockscreenWallpaper mLockscreenWallpaper; - @VisibleForTesting - protected AutoHideController mAutoHideController; + private final AutoHideController mAutoHideController; private int mNaturalBarHeight = -1; @@ -360,8 +359,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected PhoneStatusBarView mStatusBarView; private int mStatusBarWindowState = WINDOW_STATE_SHOWING; protected StatusBarWindowController mStatusBarWindowController; - @VisibleForTesting - KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting DozeServiceHost mDozeServiceHost = new DozeServiceHost(); private boolean mWakeUpComingFromTouch; @@ -369,38 +367,21 @@ public class StatusBar extends SystemUI implements DemoMode, private final Object mQueueLock = new Object(); - protected StatusBarIconController mIconController; - @Inject - DozeLog mDozeLog; - @Inject - InjectionInflationController mInjectionInflater; - @Inject - PulseExpansionHandler mPulseExpansionHandler; - @Inject - NotificationWakeUpCoordinator mWakeUpCoordinator; - @Inject - KeyguardBypassController mKeyguardBypassController; - @Inject - KeyguardStateController mKeyguardStateController; - @Inject - protected HeadsUpManagerPhone mHeadsUpManager; - @Inject - DynamicPrivacyController mDynamicPrivacyController; - @Inject - BypassHeadsUpNotifier mBypassHeadsUpNotifier; - @Nullable - @Inject - protected KeyguardLiftController mKeyguardLiftController; - @Inject - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) - boolean mAllowNotificationLongPress; - @Inject - protected NotifPipelineInitializer mNotifPipelineInitializer; - @Inject - protected FalsingManager mFalsingManager; - - @VisibleForTesting - BroadcastDispatcher mBroadcastDispatcher; + private final StatusBarIconController mIconController; + private final DozeLog mDozeLog; + private final InjectionInflationController mInjectionInflater; + private final PulseExpansionHandler mPulseExpansionHandler; + private final NotificationWakeUpCoordinator mWakeUpCoordinator; + private final KeyguardBypassController mKeyguardBypassController; + private final KeyguardStateController mKeyguardStateController; + private final HeadsUpManagerPhone mHeadsUpManager; + private final DynamicPrivacyController mDynamicPrivacyController; + private final BypassHeadsUpNotifier mBypassHeadsUpNotifier; + private final boolean mAllowNotificationLongPress; + private final NotifPipelineInitializer mNotifPipelineInitializer; + private final FalsingManager mFalsingManager; + private final BroadcastDispatcher mBroadcastDispatcher; + private final ConfigurationController mConfigurationController; // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -413,8 +394,7 @@ public class StatusBar extends SystemUI implements DemoMode, // RemoteInputView to be activated after unlock private View mPendingRemoteInputView; - private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler = - Dependency.get(RemoteInputQuickSettingsDisabler.class); + private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private View mReportRejectedTouch; @@ -423,18 +403,17 @@ public class StatusBar extends SystemUI implements DemoMode, private final int[] mAbsPos = new int[2]; private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); - private NotificationGutsManager mGutsManager; - protected NotificationLogger mNotificationLogger; - protected NotificationEntryManager mEntryManager; + private final NotificationGutsManager mGutsManager; + private final NotificationLogger mNotificationLogger; + private final NotificationEntryManager mEntryManager; private NotificationListController mNotificationListController; - private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - protected NotificationViewHierarchyManager mViewHierarchyManager; - protected ForegroundServiceController mForegroundServiceController; - protected AppOpsController mAppOpsController; - protected KeyguardViewMediator mKeyguardViewMediator; - private ZenModeController mZenController; - private final NotificationAlertingManager mNotificationAlertingManager = - Dependency.get(NotificationAlertingManager.class); + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationViewHierarchyManager mViewHierarchyManager; + private final ForegroundServiceController mForegroundServiceController; + private final AppOpsController mAppOpsController; + private final KeyguardViewMediator mKeyguardViewMediator; + private final ZenModeController mZenController; + private final NotificationAlertingManager mNotificationAlertingManager; // for disabling the status bar private int mDisabled1 = 0; @@ -445,7 +424,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Rect mLastFullscreenStackBounds = new Rect(); private final Rect mLastDockedStackBounds = new Rect(); - private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class); + private final DisplayMetrics mDisplayMetrics; // XXX: gesture research private final GestureRecorder mGestureRec = DEBUG_GESTURES @@ -454,7 +433,7 @@ public class StatusBar extends SystemUI implements DemoMode, private ScreenPinningRequest mScreenPinningRequest; - private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); + private final MetricsLogger mMetricsLogger; // ensure quick settings is disabled until the current user makes it through the setup wizard @VisibleForTesting @@ -491,14 +470,14 @@ public class StatusBar extends SystemUI implements DemoMode, private ViewMediatorCallback mKeyguardViewMediatorCallback; protected ScrimController mScrimController; protected DozeScrimController mDozeScrimController; - private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); + private final UiOffloadThread mUiOffloadThread; protected boolean mDozing; private boolean mDozingRequested; - private NotificationMediaManager mMediaManager; - protected NotificationLockscreenUserManager mLockscreenUserManager; - protected NotificationRemoteInputManager mRemoteInputManager; + private final NotificationMediaManager mMediaManager; + private final NotificationLockscreenUserManager mLockscreenUserManager; + private final NotificationRemoteInputManager mRemoteInputManager; private boolean mWallpaperSupported; private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() { @@ -569,18 +548,18 @@ public class StatusBar extends SystemUI implements DemoMode, }; private KeyguardUserSwitcher mKeyguardUserSwitcher; - protected UserSwitcherController mUserSwitcherController; - private NetworkController mNetworkController; - private BatteryController mBatteryController; + private final UserSwitcherController mUserSwitcherController; + private final NetworkController mNetworkController; + private final BatteryController mBatteryController; protected boolean mPanelExpanded; private UiModeManager mUiModeManager; protected boolean mIsKeyguard; private LogMaker mStatusBarStateLog; protected NotificationIconAreaController mNotificationIconAreaController; @Nullable private View mAmbientIndicationContainer; - private SysuiColorExtractor mColorExtractor; - private ScreenLifecycle mScreenLifecycle; - @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle; + private final SysuiColorExtractor mColorExtractor; + private final ScreenLifecycle mScreenLifecycle; + private final WakefulnessLifecycle mWakefulnessLifecycle; private final View.OnClickListener mGoToLockedShadeListener = v -> { if (mState == StatusBarState.KEYGUARD) { @@ -589,8 +568,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; private boolean mNoAnimationOnNextBarModeChange; - private final SysuiStatusBarStateController mStatusBarStateController = - (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); + private final SysuiStatusBarStateController mStatusBarStateController; private final KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -611,19 +589,14 @@ public class StatusBar extends SystemUI implements DemoMode, private HeadsUpAppearanceController mHeadsUpAppearanceController; private boolean mVibrateOnOpening; - private VibratorHelper mVibratorHelper; + private final VibratorHelper mVibratorHelper; private ActivityLaunchAnimator mActivityLaunchAnimator; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private boolean mPulsing; - protected BubbleController mBubbleController; - private final BubbleController.BubbleExpandListener mBubbleExpandListener = - (isExpanding, key) -> { - mEntryManager.updateNotifications(); - updateScrimController(); - }; + private final BubbleController mBubbleController; + private final BubbleController.BubbleExpandListener mBubbleExpandListener; private ActivityIntentHelper mActivityIntentHelper; - private ShadeController mShadeController; @Override public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { @@ -639,43 +612,129 @@ public class StatusBar extends SystemUI implements DemoMode, AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION}; + @Inject + public StatusBar( + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + InjectionInflationController injectionInflationController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + NotifPipelineInitializer notifPipelineInitializer, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController) { + mLightBarController = lightBarController; + mAutoHideController = autoHideController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mIconController = statusBarIconController; + mDozeLog = dozeLog; + mInjectionInflater = injectionInflationController; + mPulseExpansionHandler = pulseExpansionHandler; + mWakeUpCoordinator = notificationWakeUpCoordinator; + mKeyguardBypassController = keyguardBypassController; + mKeyguardStateController = keyguardStateController; + mHeadsUpManager = headsUpManagerPhone; + mDynamicPrivacyController = dynamicPrivacyController; + mBypassHeadsUpNotifier = bypassHeadsUpNotifier; + mAllowNotificationLongPress = allowNotificationLongPress; + mNotifPipelineInitializer = notifPipelineInitializer; + mFalsingManager = falsingManager; + mBroadcastDispatcher = broadcastDispatcher; + mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; + mGutsManager = notificationGutsManager; + mNotificationLogger = notificationLogger; + mEntryManager = notificationEntryManager; + mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mViewHierarchyManager = notificationViewHierarchyManager; + mForegroundServiceController = foregroundServiceController; + mAppOpsController = appOpsController; + mKeyguardViewMediator = keyguardViewMediator; + mZenController = zenModeController; + mNotificationAlertingManager = notificationAlertingManager; + mDisplayMetrics = displayMetrics; + mMetricsLogger = metricsLogger; + mUiOffloadThread = uiOffloadThread; + mMediaManager = notificationMediaManager; + mLockscreenUserManager = lockScreenUserManager; + mRemoteInputManager = remoteInputManager; + mUserSwitcherController = userSwitcherController; + mNetworkController = networkController; + mBatteryController = batteryController; + mColorExtractor = colorExtractor; + mScreenLifecycle = screenLifecycle; + mWakefulnessLifecycle = wakefulnessLifecycle; + mStatusBarStateController = statusBarStateController; + mVibratorHelper = vibratorHelper; + mBubbleController = bubbleController; + mGroupManager = groupManager; + mGroupAlertTransferHelper = groupAlertTransferHelper; + mVisualStabilityManager = visualStabilityManager; + mDeviceProvisionedController = deviceProvisionedController; + mNavigationBarController = navigationBarController; + mAssistManager = assistManager; + mNotificationListener = notificationListener; + mConfigurationController = configurationController; + mStatusBarWindowController = statusBarWindowController; + + mBubbleExpandListener = + (isExpanding, key) -> { + mEntryManager.updateNotifications(); + updateScrimController(); + }; + } + @Override public void start() { - mGroupManager = Dependency.get(NotificationGroupManager.class); - mGroupAlertTransferHelper = Dependency.get(NotificationGroupAlertTransferHelper.class); - mVisualStabilityManager = Dependency.get(VisualStabilityManager.class); - mNotificationLogger = Dependency.get(NotificationLogger.class); - mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class); - mNotificationListener = Dependency.get(NotificationListener.class); mNotificationListener.registerAsSystemService(); - mNetworkController = Dependency.get(NetworkController.class); - mUserSwitcherController = Dependency.get(UserSwitcherController.class); - mScreenLifecycle = Dependency.get(ScreenLifecycle.class); mScreenLifecycle.addObserver(mScreenObserver); - mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); - mBatteryController = Dependency.get(BatteryController.class); - mAssistManager = Dependency.get(AssistManager.class); mUiModeManager = mContext.getSystemService(UiModeManager.class); - mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); - mGutsManager = Dependency.get(NotificationGutsManager.class); - mMediaManager = Dependency.get(NotificationMediaManager.class); - mEntryManager = Dependency.get(NotificationEntryManager.class); mBypassHeadsUpNotifier.setUp(mEntryManager); - mNotificationInterruptionStateProvider = - Dependency.get(NotificationInterruptionStateProvider.class); - mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class); - mForegroundServiceController = Dependency.get(ForegroundServiceController.class); - mAppOpsController = Dependency.get(AppOpsController.class); - mZenController = Dependency.get(ZenModeController.class); - mKeyguardViewMediator = getComponent(KeyguardViewMediator.class); - mColorExtractor = Dependency.get(SysuiColorExtractor.class); - mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); - mNavigationBarController = Dependency.get(NavigationBarController.class); - mBubbleController = Dependency.get(BubbleController.class); mBubbleController.setExpandListener(mBubbleExpandListener); mActivityIntentHelper = new ActivityIntentHelper(mContext); - mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class); KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance(); if (sliceProvider != null) { sliceProvider.initDependencies(mMediaManager, mStatusBarStateController, @@ -698,7 +757,6 @@ public class StatusBar extends SystemUI implements DemoMode, mVibrateOnOpening = mContext.getResources().getBoolean( R.bool.config_vibrateOnIconAnimation); - mVibratorHelper = Dependency.get(VibratorHelper.class); DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER)); putComponent(StatusBar.class, this); @@ -712,7 +770,6 @@ public class StatusBar extends SystemUI implements DemoMode, mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @@ -806,7 +863,7 @@ public class StatusBar extends SystemUI implements DemoMode, Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); - Dependency.get(ConfigurationController.class).addCallback(this); + mConfigurationController.addCallback(this); // set the initial view visibility Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications); @@ -839,6 +896,8 @@ public class StatusBar extends SystemUI implements DemoMode, NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller; mNotificationLogger.setUpWithContainer(notifListContainer); + // TODO: make this injectable. Currently that would create a circular dependency between + // NotificationIconAreaController and StatusBar. mNotificationIconAreaController = SystemUIFactory.getInstance() .createNotificationIconAreaController(context, this, mWakeUpCoordinator, mKeyguardBypassController, @@ -901,10 +960,9 @@ public class StatusBar extends SystemUI implements DemoMode, .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG) .commit(); - mIconController = Dependency.get(StatusBarIconController.class); mHeadsUpManager.setUp(mStatusBarWindow, mGroupManager, this, mVisualStabilityManager); - Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager); + mConfigurationController.addCallback(mHeadsUpManager); mHeadsUpManager.addListener(this); mHeadsUpManager.addListener(mNotificationPanel); mHeadsUpManager.addListener(mGroupManager); @@ -947,11 +1005,8 @@ public class StatusBar extends SystemUI implements DemoMode, } }); - mAutoHideController = Dependency.get(AutoHideController.class); mAutoHideController.setStatusBar(this); - mLightBarController = Dependency.get(LightBarController.class); - ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind); ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front); ScrimView scrimForBubble = mStatusBarWindow.findViewById(R.id.scrim_for_bubble); @@ -1042,11 +1097,10 @@ public class StatusBar extends SystemUI implements DemoMode, }); } - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - if (!pm.isScreenOn()) { + if (!mPowerManager.isScreenOn()) { mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF)); } - mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, + mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GestureWakeLock"); mVibrator = mContext.getSystemService(Vibrator.class); int[] pattern = mContext.getResources().getIntArray( @@ -1123,7 +1177,6 @@ public class StatusBar extends SystemUI implements DemoMode, final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback = (StatusBarRemoteInputCallback) Dependency.get( NotificationRemoteInputManager.Callback.class); - mShadeController = Dependency.get(ShadeController.class); final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext, @@ -1131,7 +1184,7 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager, activityStarter, mActivityLaunchAnimator, mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager, mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager, - mLockscreenUserManager, mShadeController, mKeyguardStateController, + mLockscreenUserManager, this, mKeyguardStateController, mNotificationInterruptionStateProvider, mMetricsLogger, new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER), Dependency.get(BG_HANDLER), mActivityIntentHelper, mBubbleController); @@ -1140,7 +1193,7 @@ public class StatusBar extends SystemUI implements DemoMode, mEntryManager.setRowBinder(rowBinder); rowBinder.setNotificationClicker(new NotificationClicker( - this, Dependency.get(BubbleController.class), mNotificationActivityStarter)); + this, mBubbleController, mNotificationActivityStarter)); mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager); mNotificationListController.bind(); @@ -1170,8 +1223,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void wakeUpIfDozing(long time, View where, String why) { if (mDozing) { - PowerManager pm = mContext.getSystemService(PowerManager.class); - pm.wakeUp(time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); + mPowerManager.wakeUp( + time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); mWakeUpComingFromTouch = true; where.getLocationInWindow(mTmpInt2); mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2, @@ -1271,13 +1324,12 @@ public class StatusBar extends SystemUI implements DemoMode, protected void startKeyguard() { Trace.beginSection("StatusBar#startKeyguard"); - KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mBiometricUnlockController = new BiometricUnlockController(mContext, - mDozeScrimController, keyguardViewMediator, + mDozeScrimController, mKeyguardViewMediator, mScrimController, this, mKeyguardStateController, new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController); putComponent(BiometricUnlockController.class, mBiometricUnlockController); - mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, + mStatusBarKeyguardViewManager = mKeyguardViewMediator.registerStatusBar(this, getBouncerContainer(), mNotificationPanel, mBiometricUnlockController, mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller, mKeyguardBypassController); @@ -1287,7 +1339,7 @@ public class StatusBar extends SystemUI implements DemoMode, mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); - mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); + mKeyguardViewMediatorCallback = mKeyguardViewMediator.getViewMediatorCallback(); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); mMediaManager.setBiometricUnlockController(mBiometricUnlockController); Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked); @@ -1773,6 +1825,16 @@ public class StatusBar extends SystemUI implements DemoMode, return mPresenter; } + @VisibleForTesting + void setBarStateForTest(int state) { + mState = state; + } + + @VisibleForTesting + void setUserSetupForTest(boolean userSetup) { + mUserSetup = userSetup; + } + /** * All changes to the status bar and notifications funnel through here and are batched. */ @@ -2464,7 +2526,6 @@ public class StatusBar extends SystemUI implements DemoMode, public void createAndAddWindows(@Nullable RegisterStatusBarResult result) { makeStatusBarView(result); - mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); } @@ -2708,7 +2769,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - // SystemUIService notifies SystemBars of configuration changes, which then calls down here @Override public void onConfigChanged(Configuration newConfig) { updateResources(); @@ -3290,7 +3350,7 @@ public class StatusBar extends SystemUI implements DemoMode, final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; if (mContext.getThemeResId() != themeResId) { mContext.setTheme(themeResId); - Dependency.get(ConfigurationController.class).notifyThemeChanged(); + mConfigurationController.notifyThemeChanged(); } } @@ -3837,8 +3897,7 @@ public class StatusBar extends SystemUI implements DemoMode, return; } if (!mDeviceInteractive) { - PowerManager pm = mContext.getSystemService(PowerManager.class); - pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, + mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, "com.android.systemui:CAMERA_GESTURE"); } vibrateForCameraGesture(); @@ -4227,12 +4286,11 @@ public class StatusBar extends SystemUI implements DemoMode, // all notifications protected ViewGroup mStackScroller; - protected NotificationGroupManager mGroupManager; - - protected NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; + private final NotificationGroupManager mGroupManager; + private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; // handling reordering - protected VisualStabilityManager mVisualStabilityManager; + private final VisualStabilityManager mVisualStabilityManager; protected AccessibilityManager mAccessibilityManager; @@ -4248,10 +4306,9 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected KeyguardManager mKeyguardManager; - private DeviceProvisionedController mDeviceProvisionedController - = Dependency.get(DeviceProvisionedController.class); + private final DeviceProvisionedController mDeviceProvisionedController; - protected NavigationBarController mNavigationBarController; + private final NavigationBarController mNavigationBarController; // UI-specific methods @@ -4267,7 +4324,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationShelf mNotificationShelf; protected EmptyShadeView mEmptyShadeView; - protected AssistManager mAssistManager; + private final AssistManager mAssistManager; public boolean isDeviceInteractive() { return mDeviceInteractive; @@ -4326,7 +4383,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - protected NotificationListener mNotificationListener; + private final NotificationListener mNotificationListener; public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) { if (snoozeOption.getSnoozeCriterion() != null) { @@ -4462,8 +4519,7 @@ public class StatusBar extends SystemUI implements DemoMode, executeActionDismissingKeyguard(() -> { try { intent.send(null, 0, null, null, null, null, getActivityOptions( - mActivityLaunchAnimator.getLaunchAnimation(associatedView, - mShadeController.isOccluded()))); + mActivityLaunchAnimator.getLaunchAnimation(associatedView, isOccluded()))); } catch (PendingIntent.CanceledException e) { // the stack trace isn't very helpful here. // Just log the exception message. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index df23f8caefeb..75b0cdcf13bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -61,6 +61,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.PrintWriter; import java.util.ArrayList; +import androidx.annotation.VisibleForTesting; + /** * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, @@ -160,6 +162,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastLockVisible; private OnDismissAction mAfterKeyguardGoneAction; + private Runnable mKeyguardGoneCancelAction; private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); // Dismiss action to be launched when we stop dozing or the keyguard is gone. @@ -329,10 +332,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return false; } - private void hideBouncer(boolean destroyView) { + @VisibleForTesting + void hideBouncer(boolean destroyView) { if (mBouncer == null) { return; } + if (mShowing) { + // If we were showing the bouncer and then aborting, we need to also clear out any + // potential actions unless we actually unlocked. + mAfterKeyguardGoneAction = null; + if (mKeyguardGoneCancelAction != null) { + mKeyguardGoneCancelAction.run(); + mKeyguardGoneCancelAction = null; + } + } mBouncer.hide(destroyView); cancelPendingWakeupAction(); } @@ -365,6 +378,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.showWithDismissAction(r, cancelAction); } else { mAfterKeyguardGoneAction = r; + mKeyguardGoneCancelAction = cancelAction; mBouncer.show(false /* resetSecuritySelection */); } } @@ -672,6 +686,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mAfterKeyguardGoneAction.onDismiss(); mAfterKeyguardGoneAction = null; } + mKeyguardGoneCancelAction = null; for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { mAfterKeyguardGoneRunnables.get(i).run(); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index a46f018af816..cd1f0cc13297 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -21,6 +21,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.PermissionChecker; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.hardware.usb.IUsbManager; @@ -84,14 +85,27 @@ public class UsbPermissionActivity extends AlertActivity final AlertController.AlertParams ap = mAlertParams; ap.mTitle = appName; if (mDevice == null) { + // Accessory Case + ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName, mAccessory.getDescription()); mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory); } else { - ap.mMessage = getString(R.string.usb_device_permission_prompt, appName, - mDevice.getProductName()); + boolean hasRecordPermission = + PermissionChecker.checkPermission( + this, android.Manifest.permission.RECORD_AUDIO, -1, aInfo.uid, + mPackageName) + == android.content.pm.PackageManager.PERMISSION_GRANTED; + boolean isAudioCaptureDevice = mDevice.getHasAudioCapture(); + boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission; + + int strID = useRecordWarning + ? R.string.usb_device_permission_prompt_warn + : R.string.usb_device_permission_prompt; + ap.mMessage = getString(strID, appName, mDevice.getProductName()); mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice); } + ap.mPositiveButtonText = getString(android.R.string.ok); ap.mNegativeButtonText = getString(android.R.string.cancel); ap.mPositiveButtonListener = this; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 2e94c7c12cd8..38537fdb00b1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -26,20 +26,24 @@ import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Process; import android.provider.Settings; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -62,6 +66,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; import java.util.ArrayList; import java.util.HashMap; @@ -105,6 +110,14 @@ public class CarrierTextControllerTest extends SysuiTestCase { private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; + private Void checkMainThread(InvocationOnMock inv) { + Looper mainLooper = Dependency.get(Dependency.MAIN_HANDLER).getLooper(); + if (!mainLooper.isCurrentThread()) { + fail("This call should be done from the main thread"); + } + return null; + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -112,6 +125,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); + when(mConnectivityManager.isNetworkSupported(anyInt())).thenReturn(true); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mContext.getOrCreateTestableResources().addOverride( @@ -121,19 +135,43 @@ public class CarrierTextControllerTest extends SysuiTestCase { mDependency.injectMockDependency(WakefulnessLifecycle.class); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, new Handler(mTestableLooper.getLooper())); - mDependency.injectMockDependency(KeyguardUpdateMonitor.class); + mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); + + doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) + .registerCallback(any(KeyguardUpdateMonitorCallback.class)); + doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) + .removeCallback(any(KeyguardUpdateMonitorCallback.class)); mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); - when(mTelephonyManager.getPhoneCount()).thenReturn(3); + when(mTelephonyManager.getMaxPhoneCount()).thenReturn(3); - mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true, - mKeyguardUpdateMonitor); - // This should not start listening on any of the real dependencies + mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true); + // This should not start listening on any of the real dependencies but will test that + // callbacks in mKeyguardUpdateMonitor are done in the mTestableLooper thread mCarrierTextController.setListening(mCarrierTextCallback); } @Test + public void testKeyguardUpdateMonitorCalledInMainThread() throws Exception { + // This test will run on the main looper (which is not the same as the looper set as MAIN + // for CarrierTextCallback. This will fail if calls to mKeyguardUpdateMonitor are not done + // through the looper set in the set up + HandlerThread thread = new HandlerThread("testThread", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + TestableLooper testableLooper = new TestableLooper(thread.getLooper()); + Handler h = new Handler(testableLooper.getLooper()); + h.post(() -> { + mCarrierTextController.setListening(null); + mCarrierTextController.setListening(mCarrierTextCallback); + }); + testableLooper.processAllMessages(); + mTestableLooper.processAllMessages(); + thread.quitSafely(); + } + + @Test public void testAirplaneMode() { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); reset(mCarrierTextCallback); @@ -466,20 +504,4 @@ public class CarrierTextControllerTest extends SysuiTestCase { assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER, captor.getValue().carrierText); } - - public static class TestCarrierTextController extends CarrierTextController { - private KeyguardUpdateMonitor mKUM; - - public TestCarrierTextController(Context context, CharSequence separator, - boolean showAirplaneMode, boolean showMissingSim, KeyguardUpdateMonitor kum) { - super(context, separator, showAirplaneMode, showMissingSim); - mKUM = kum; - } - - @Override - public void setListening(CarrierTextCallback callback) { - super.setListening(callback); - mKeyguardUpdateMonitor = mKUM; - } - } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index ad7bba1e0790..57b09872f9c1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; @@ -481,6 +482,25 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.isUserUnlocked(randomUser)).isFalse(); } + @Test + public void testTrustUsuallyManaged_whenTrustChanges() { + int user = KeyguardUpdateMonitor.getCurrentUser(); + when(mTrustManager.isTrustUsuallyManaged(eq(user))).thenReturn(true); + mKeyguardUpdateMonitor.onTrustManagedChanged(false /* managed */, user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isTrue(); + } + + @Test + public void testTrustUsuallyManaged_resetWhenUserIsRemoved() { + int user = KeyguardUpdateMonitor.getCurrentUser(); + when(mTrustManager.isTrustUsuallyManaged(eq(user))).thenReturn(true); + mKeyguardUpdateMonitor.onTrustManagedChanged(false /* managed */, user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isTrue(); + + mKeyguardUpdateMonitor.handleUserRemoved(user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isFalse(); + } + private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) { int subscription = simInited ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java index 7d2ccdc8f0a9..618272cbcab0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -240,4 +241,10 @@ public class NavigationBarControllerTest extends SysuiTestCase { verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L)); } + + @Test + public void testGetAssistHandlerViewController_noCrash() { + reset(mNavigationBarController.mNavigationBars); + mNavigationBarController.getAssistHandlerViewController(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 3ba3e281dc81..cb87d7d842a4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -89,6 +89,8 @@ public class KeyguardBouncerTest extends SysuiTestCase { private KeyguardBypassController mKeyguardBypassController; @Mock private Handler mHandler; + @Mock + private KeyguardSecurityModel mKeyguardSecurityModel; private KeyguardBouncer mBouncer; @@ -97,6 +99,9 @@ public class KeyguardBouncerTest extends SysuiTestCase { com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); MockitoAnnotations.initMocks(this); mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); + mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel); + when(mKeyguardSecurityModel.getSecurityMode(anyInt())) + .thenReturn(KeyguardSecurityModel.SecurityMode.None); DejankUtils.setImmediate(true); final ViewGroup container = new FrameLayout(getContext()); when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver); @@ -306,14 +311,6 @@ public class KeyguardBouncerTest extends SysuiTestCase { } @Test - public void testNeedsFullscreenBouncer_asksKeyguardView() { - mBouncer.ensureView(); - mBouncer.needsFullscreenBouncer(); - verify(mKeyguardHostView).getSecurityMode(); - verify(mKeyguardHostView, never()).getCurrentSecurityMode(); - } - - @Test public void testIsFullscreenBouncer_asksKeyguardView() { mBouncer.ensureView(); mBouncer.isFullscreenBouncer(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 0bff5aa9e991..237f6ac0f420 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -80,7 +80,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) -@RunWithLooper() +@RunWithLooper(setAsMainLooper = true) @SmallTest public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { private static final int EXTERNAL_DISPLAY_ID = 2; @@ -217,7 +217,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for default NavBar. mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false); - Handler.getMain().runWithScissors(() -> { }, 500); + processAllMessages(); // Verify IME window state will be updated in default NavBar & external NavBar state reset. assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, @@ -228,7 +228,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { // Set IME window status for external NavBar. mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false); - Handler.getMain().runWithScissors(() -> { }, 500); + processAllMessages(); // Verify IME window state will be updated in external NavBar & default NavBar state reset. assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 4140b0d4ace1..214e26a4a2b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -46,6 +46,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.util.function.TriConsumer; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -95,6 +96,7 @@ public class ScrimControllerTest extends SysuiTestCase { mDependency.injectMockDependency(KeyguardUpdateMonitor.class); when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled); when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true); + DejankUtils.setImmediate(true); mScrimController = new SynchronousScrimController(mScrimBehind, mScrimInFront, mScrimForBubble, (scrimState, scrimBehindAlpha, scrimInFrontColor) -> { @@ -113,6 +115,7 @@ public class ScrimControllerTest extends SysuiTestCase { @After public void tearDown() { mScrimController.finishAnimationsImmediately(); + DejankUtils.setImmediate(false); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index c3b25ce56714..aafcdd09fc10 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -227,6 +227,31 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mStatusBar, never()).animateKeyguardUnoccluding(); } + @Test + public void testHiding_cancelsGoneRunnable() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hideBouncer(true); + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action, never()).onDismiss(); + verify(cancelAction).run(); + } + + @Test + public void testHiding_doesntCancelWhenShowing() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action).onDismiss(); + verify(cancelAction, never()).run(); + } + private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { public TestableStatusBarKeyguardViewManager(Context context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 7de7f9e23813..144935212c27 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -59,12 +59,13 @@ import android.support.test.metricshelper.MetricsAsserts; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.util.DisplayMetrics; import android.util.SparseArray; import android.view.ViewGroup.LayoutParams; import androidx.test.filters.SmallTest; -import com.android.internal.logging.MetricsLogger; +import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.internal.statusbar.IStatusBarService; @@ -73,19 +74,21 @@ import com.android.systemui.Dependency; import com.android.systemui.ForegroundServiceController; import com.android.systemui.InitController; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.UiOffloadThread; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; +import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -96,16 +99,21 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -114,9 +122,14 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -135,6 +148,15 @@ import java.util.HashSet; @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) public class StatusBarTest extends SysuiTestCase { + + private StatusBar mStatusBar; + private FakeMetricsLogger mMetricsLogger; + private PowerManager mPowerManager; + private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private CommandQueue mCommandQueue; + + @Mock private LightBarController mLightBarController; + @Mock private StatusBarIconController mStatusBarIconController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private KeyguardStateController mKeyguardStateController; @Mock private KeyguardIndicationController mKeyguardIndicationController; @@ -148,11 +170,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ArrayList<NotificationEntry> mNotificationList; @Mock private BiometricUnlockController mBiometricUnlockController; @Mock private NotificationData mNotificationData; - @Mock - private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; - - // Mock dependencies: - @Mock private NotificationViewHierarchyManager mViewHierarchyManager; + @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationListener mNotificationListener; @Mock private KeyguardViewMediator mKeyguardViewMediator; @@ -163,51 +181,46 @@ public class StatusBarTest extends SysuiTestCase { @Mock private BatteryController mBatteryController; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private StatusBarNotificationPresenter mNotificationPresenter; - @Mock - private NotificationEntryListener mEntryListener; - @Mock - private NotificationFilter mNotificationFilter; - @Mock - private NotificationAlertingManager mNotificationAlertingManager; - @Mock - private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; - @Mock - private KeyguardUpdateMonitor mKeyguardUpdateMonitor; - @Mock - private AmbientDisplayConfiguration mAmbientDisplayConfiguration; - @Mock - private StatusBarWindowView mStatusBarWindowView; - @Mock - private BroadcastDispatcher mBroadcastDispatcher; - - private TestableStatusBar mStatusBar; - private FakeMetricsLogger mMetricsLogger; - private PowerManager mPowerManager; - private TestableNotificationEntryManager mEntryManager; - private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - private NotificationLogger mNotificationLogger; - private CommandQueue mCommandQueue; + @Mock private NotificationEntryListener mEntryListener; + @Mock private NotificationFilter mNotificationFilter; + @Mock private NotificationAlertingManager mNotificationAlertingManager; + @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration; + @Mock private StatusBarWindowView mStatusBarWindowView; + @Mock private BroadcastDispatcher mBroadcastDispatcher; + @Mock private AssistManager mAssistManager; + @Mock private NotificationGutsManager mNotificationGutsManager; + @Mock private NotificationMediaManager mNotificationMediaManager; + @Mock private ForegroundServiceController mForegroundServiceController; + @Mock private AppOpsController mAppOpsController; + @Mock private NavigationBarController mNavigationBarController; + @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier; + @Mock private SysuiColorExtractor mColorExtractor; + @Mock private ColorExtractor.GradientColors mGradientColors; + @Mock private DozeLog mDozeLog; + @Mock private PulseExpansionHandler mPulseExpansionHandler; + @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; + @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock private InjectionInflationController mInjectionInflationController; + @Mock private DynamicPrivacyController mDynamicPrivacyController; + @Mock private NotifPipelineInitializer mNotifPipelineInitializer; + @Mock private ZenModeController mZenModeController; + @Mock private AutoHideController mAutoHideController; + @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager; + @Mock private UserSwitcherController mUserSwitcherController; + @Mock private NetworkController mNetworkController; + @Mock private VibratorHelper mVibratorHelper; + @Mock private BubbleController mBubbleController; + @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; + @Mock private StatusBarWindowController mStatusBarWindowController; + @Mock private NotificationIconAreaController mNotificationIconAreaController; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(AssistManager.class); - mDependency.injectMockDependency(NotificationGutsManager.class); - mDependency.injectMockDependency(NotificationMediaManager.class); - mDependency.injectMockDependency(ForegroundServiceController.class); - mDependency.injectTestDependency(NotificationViewHierarchyManager.class, - mViewHierarchyManager); - mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager); - mDependency.injectTestDependency(NotificationListener.class, mNotificationListener); - mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsController.class)); - mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); - mDependency.injectTestDependency(DeviceProvisionedController.class, - mDeviceProvisionedController); - mDependency.injectMockDependency(BubbleController.class); mDependency.injectTestDependency(NotificationFilter.class, mNotificationFilter); - mDependency.injectTestDependency(NotificationAlertingManager.class, - mNotificationAlertingManager); - mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher); IPowerManager powerManagerService = mock(IPowerManager.class); mPowerManager = new PowerManager(mContext, powerManagerService, @@ -217,21 +230,17 @@ public class StatusBarTest extends SysuiTestCase { new TestableNotificationInterruptionStateProvider(mContext, mPowerManager, mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter, mStatusBarStateController, mBatteryController); - mDependency.injectTestDependency(NotificationInterruptionStateProvider.class, - mNotificationInterruptionStateProvider); - mDependency.injectMockDependency(NavigationBarController.class); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); mMetricsLogger = new FakeMetricsLogger(); - mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); - mEntryManager = new TestableNotificationEntryManager(mContext); - mNotificationLogger = new NotificationLogger(mNotificationListener, - Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController, + TestableNotificationEntryManager entryManager = new TestableNotificationEntryManager( + mContext); + NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, + Dependency.get(UiOffloadThread.class), entryManager, mStatusBarStateController, mExpansionStateLogger); - mNotificationLogger.setVisibilityReporter(mock(Runnable.class)); - mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger); + notificationLogger.setVisibilityReporter(mock(Runnable.class)); mCommandQueue = mock(CommandQueue.class); when(mCommandQueue.asBinder()).thenReturn(new Binder()); @@ -260,32 +269,94 @@ public class StatusBarTest extends SysuiTestCase { mHeadsUpManager, mHeadsUpSuppressor); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, - mKeyguardIndicationController, mStackScroller, - mPowerManager, mNotificationPanelView, mBarService, mNotificationListener, - mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager, - mEntryManager, mScrimController, mBiometricUnlockController, - mKeyguardViewMediator, mRemoteInputManager, mock(NotificationGroupManager.class), - mock(NotificationGroupAlertTransferHelper.class), mock(FalsingManager.class), - mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class), - mDozeScrimController, mock(NotificationShelf.class), - mLockscreenUserManager, mCommandQueue, mNotificationPresenter, - mock(BubbleController.class), mock(NavigationBarController.class), - mock(AutoHideController.class), mKeyguardUpdateMonitor, mStatusBarWindowView, - mBroadcastDispatcher); + + WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle(); + wakefulnessLifecycle.dispatchStartedWakingUp(); + wakefulnessLifecycle.dispatchFinishedWakingUp(); + + when(mGradientColors.supportsDarkText()).thenReturn(true); + when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + ConfigurationController configurationController = new ConfigurationControllerImpl(mContext); + + mStatusBar = new StatusBar( + mLightBarController, + mAutoHideController, + mKeyguardUpdateMonitor, + mStatusBarIconController, + mDozeLog, + mInjectionInflationController, + mPulseExpansionHandler, + mNotificationWakeUpCoordinator, + mKeyguardBypassController, + mKeyguardStateController, + mHeadsUpManager, + mDynamicPrivacyController, + mBypassHeadsUpNotifier, + true, + mNotifPipelineInitializer, + new FalsingManagerFake(), + mBroadcastDispatcher, + new RemoteInputQuickSettingsDisabler( + mContext, + configurationController + ), + mNotificationGutsManager, + notificationLogger, + entryManager, + mNotificationInterruptionStateProvider, + mNotificationViewHierarchyManager, + mForegroundServiceController, + mAppOpsController, + mKeyguardViewMediator, + mZenModeController, + mNotificationAlertingManager, + new DisplayMetrics(), + mMetricsLogger, + Dependency.get(UiOffloadThread.class), + mNotificationMediaManager, + mLockscreenUserManager, + mRemoteInputManager, + mUserSwitcherController, + mNetworkController, + mBatteryController, + mColorExtractor, + new ScreenLifecycle(), + wakefulnessLifecycle, + mStatusBarStateController, + mVibratorHelper, + mBubbleController, + mGroupManager, + mGroupAlertTransferHelper, + mVisualStabilityManager, + mDeviceProvisionedController, + mNavigationBarController, + mAssistManager, + mNotificationListener, + configurationController, + mStatusBarWindowController); + // TODO: we should be able to call mStatusBar.start() and have all the below values + // initialized automatically. mStatusBar.mContext = mContext; mStatusBar.mComponents = mContext.getComponents(); - SystemUIFactory.getInstance().getRootComponent() - .getStatusBarInjector() - .createStatusBar(mStatusBar); - mStatusBar.mKeyguardStateController = mKeyguardStateController; - mStatusBar.setHeadsUpManager(mHeadsUpManager); + mStatusBar.mStatusBarKeyguardViewManager = mStatusBarKeyguardViewManager; + mStatusBar.mStatusBarWindow = mStatusBarWindowView; + mStatusBar.mBiometricUnlockController = mBiometricUnlockController; + mStatusBar.mScrimController = mScrimController; + mStatusBar.mNotificationPanel = mNotificationPanelView; + mStatusBar.mCommandQueue = mCommandQueue; + mStatusBar.mDozeScrimController = mDozeScrimController; + mStatusBar.mNotificationIconAreaController = mNotificationIconAreaController; + mStatusBar.mPresenter = mNotificationPresenter; + mStatusBar.mKeyguardIndicationController = mKeyguardIndicationController; + mStatusBar.mPowerManager = mPowerManager; + mStatusBar.mBarService = mBarService; + mStatusBar.mStackScroller = mStackScroller; mStatusBar.putComponent(StatusBar.class, mStatusBar); Dependency.get(InitController.class).executePostInitTasks(); - mEntryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller, + entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller, mHeadsUpManager, mNotificationData); - mEntryManager.addNotificationEntryListener(mEntryListener); - mNotificationLogger.setUpWithContainer(mStackScroller); + entryManager.addNotificationEntryListener(mEntryListener); + notificationLogger.setUpWithContainer(mStackScroller); } @Test @@ -608,8 +679,8 @@ public class StatusBarTest extends SysuiTestCase { @Test @RunWithLooper(setAsMainLooper = true) public void testUpdateKeyguardState_DoesNotCrash() { - mStatusBar.mState = StatusBarState.KEYGUARD; - when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn( + mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + when(mLockscreenUserManager.getCurrentProfiles()).thenReturn( new SparseArray<>()); mStatusBar.onStateChanged(StatusBarState.SHADE); } @@ -740,8 +811,7 @@ public class StatusBarTest extends SysuiTestCase { verify(mStatusBarStateController).setState(eq(StatusBarState.KEYGUARD)); // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER. - mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class); - when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); + when(mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); mStatusBar.showKeyguardImpl(); verify(mStatusBarStateController).setState(eq(StatusBarState.FULLSCREEN_USER_SWITCHER)); } @@ -793,97 +863,6 @@ public class StatusBarTest extends SysuiTestCase { any(UserHandle.class)); } - static class TestableStatusBar extends StatusBar { - public TestableStatusBar(StatusBarKeyguardViewManager man, - KeyguardIndicationController key, - NotificationStackScrollLayout stack, - PowerManager pm, NotificationPanelView panelView, - IStatusBarService barService, NotificationListener notificationListener, - NotificationLogger notificationLogger, - VisualStabilityManager visualStabilityManager, - NotificationViewHierarchyManager viewHierarchyManager, - TestableNotificationEntryManager entryManager, ScrimController scrimController, - BiometricUnlockController biometricUnlockController, - KeyguardViewMediator keyguardViewMediator, - NotificationRemoteInputManager notificationRemoteInputManager, - NotificationGroupManager notificationGroupManager, - NotificationGroupAlertTransferHelper notificationGroupAlertTransferHelper, - FalsingManager falsingManager, - StatusBarWindowController statusBarWindowController, - NotificationIconAreaController notificationIconAreaController, - DozeScrimController dozeScrimController, - NotificationShelf notificationShelf, - NotificationLockscreenUserManager notificationLockscreenUserManager, - CommandQueue commandQueue, - StatusBarNotificationPresenter notificationPresenter, - BubbleController bubbleController, - NavigationBarController navBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarWindowView statusBarWindow, - BroadcastDispatcher broadcastDispatcher) { - mStatusBarKeyguardViewManager = man; - mKeyguardIndicationController = key; - mStackScroller = stack; - mPowerManager = pm; - mNotificationPanel = panelView; - mBarService = barService; - mNotificationListener = notificationListener; - mNotificationLogger = notificationLogger; - mWakefulnessLifecycle = createAwakeWakefulnessLifecycle(); - mVisualStabilityManager = visualStabilityManager; - mViewHierarchyManager = viewHierarchyManager; - mEntryManager = entryManager; - mScrimController = scrimController; - mBiometricUnlockController = biometricUnlockController; - mKeyguardViewMediator = keyguardViewMediator; - mRemoteInputManager = notificationRemoteInputManager; - mGroupManager = notificationGroupManager; - mGroupAlertTransferHelper = notificationGroupAlertTransferHelper; - mFalsingManager = falsingManager; - mStatusBarWindowController = statusBarWindowController; - mNotificationIconAreaController = notificationIconAreaController; - mDozeScrimController = dozeScrimController; - mNotificationShelf = notificationShelf; - mLockscreenUserManager = notificationLockscreenUserManager; - mCommandQueue = commandQueue; - mPresenter = notificationPresenter; - mGestureWakeLock = mock(PowerManager.WakeLock.class); - mBubbleController = bubbleController; - mNavigationBarController = navBarController; - mAutoHideController = autoHideController; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mStatusBarWindow = statusBarWindow; - mDozeServiceHost.mWakeLockScreenPerformsAuth = false; - mBroadcastDispatcher = broadcastDispatcher; - } - - private WakefulnessLifecycle createAwakeWakefulnessLifecycle() { - WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle(); - wakefulnessLifecycle.dispatchStartedWakingUp(); - wakefulnessLifecycle.dispatchFinishedWakingUp(); - return wakefulnessLifecycle; - } - - @Override - protected void updateTheme() { - // Do nothing for now, until we have more mocking and StatusBar is smaller. - } - - public void setBarStateForTest(int state) { - mState = state; - } - - void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { - mHeadsUpManager = headsUpManager; - } - - public void setUserSetupForTest(boolean userSetup) { - mUserSetup = userSetup; - } - - } - public static class TestableNotificationEntryManager extends NotificationEntryManager { public TestableNotificationEntryManager(Context context) { @@ -902,7 +881,7 @@ public class StatusBarTest extends SysuiTestCase { public static class TestableNotificationInterruptionStateProvider extends NotificationInterruptionStateProvider { - public TestableNotificationInterruptionStateProvider( + TestableNotificationInterruptionStateProvider( Context context, PowerManager powerManager, IDreamManager dreamManager, diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index dc7a9aaf966d..5ac3b69549c1 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -72,10 +72,16 @@ class EventDispatcher { * * @param prototype The prototype from which to create the injected events. * @param action The action of the event. + * @param rawEvent The original event prior to magnification or other transformations. * @param pointerIdBits The bits of the pointers to send. * @param policyFlags The policy flags associated with the event. */ - void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBits, int policyFlags) { + void sendMotionEvent( + MotionEvent prototype, + int action, + MotionEvent rawEvent, + int pointerIdBits, + int policyFlags) { prototype.setAction(action); MotionEvent event = null; @@ -105,11 +111,8 @@ class EventDispatcher { // Make sure that the user will see the event. policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; - // TODO: For now pass null for the raw event since the touch - // explorer is the last event transformation and it does - // not care about the raw event. if (mReceiver != null) { - mReceiver.onMotionEvent(event, null, policyFlags); + mReceiver.onMotionEvent(event, rawEvent, policyFlags); } else { Slog.e(LOG_TAG, "Error sending event: no receiver specified."); } @@ -280,7 +283,12 @@ class EventDispatcher { if (!isInjectedPointerDown(pointerId)) { pointerIdBits |= (1 << pointerId); final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); - sendMotionEvent(prototype, action, pointerIdBits, policyFlags); + sendMotionEvent( + prototype, + action, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); } } } @@ -303,7 +311,8 @@ class EventDispatcher { } pointerIdBits |= (1 << pointerId); final int action = computeInjectionAction(MotionEvent.ACTION_UP, i); - sendMotionEvent(prototype, action, pointerIdBits, policyFlags); + sendMotionEvent( + prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index f4ac82157d04..c60e35e2cc6d 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -183,9 +183,9 @@ public class TouchExplorer extends BaseEventStreamTransformation private void clear() { // If we have not received an event then we are in initial // state. Therefore, there is not need to clean anything. - MotionEvent event = mReceivedPointerTracker.getLastReceivedEvent(); + MotionEvent event = mState.getLastReceivedEvent(); if (event != null) { - clear(mReceivedPointerTracker.getLastReceivedEvent(), WindowManagerPolicy.FLAG_TRUSTED); + clear(event, WindowManagerPolicy.FLAG_TRUSTED); } } @@ -229,7 +229,7 @@ public class TouchExplorer extends BaseEventStreamTransformation Slog.d(LOG_TAG, mState.toString()); } - mReceivedPointerTracker.onMotionEvent(rawEvent); + mState.onReceivedMotionEvent(rawEvent); if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) { // Event was handled by the gesture detector. @@ -250,9 +250,9 @@ public class TouchExplorer extends BaseEventStreamTransformation } else if (mState.isTouchExploring()) { handleMotionEventStateTouchExploring(event, rawEvent, policyFlags); } else if (mState.isDragging()) { - handleMotionEventStateDragging(event, policyFlags); + handleMotionEventStateDragging(event, rawEvent, policyFlags); } else if (mState.isDelegating()) { - handleMotionEventStateDelegating(event, policyFlags); + handleMotionEventStateDelegating(event, rawEvent, policyFlags); } else if (mState.isGestureDetecting()) { // Already handled. } else { @@ -292,7 +292,7 @@ public class TouchExplorer extends BaseEventStreamTransformation } // Pointers should not be zero when running this command. - if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) { + if (mState.getLastReceivedEvent().getPointerCount() == 0) { return; } // Try to use the standard accessibility API to long click @@ -368,11 +368,15 @@ public class TouchExplorer extends BaseEventStreamTransformation // We have just decided that the user is touch, // exploring so start sending events. - mSendHoverEnterAndMoveDelayed.addEvent(event); + mSendHoverEnterAndMoveDelayed.addEvent(event, mState.getLastReceivedEvent()); mSendHoverEnterAndMoveDelayed.forceSendAndRemove(); mSendHoverExitDelayed.cancel(); mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags); + event, + MotionEvent.ACTION_HOVER_MOVE, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); return true; } } @@ -387,7 +391,7 @@ public class TouchExplorer extends BaseEventStreamTransformation switch (event.getActionMasked()) { // The only way to leave the clear state is for a pointer to go down. case MotionEvent.ACTION_DOWN: - handleActionDown(event, policyFlags); + handleActionDown(event, rawEvent, policyFlags); break; default: // Some other nonsensical event. @@ -399,7 +403,7 @@ public class TouchExplorer extends BaseEventStreamTransformation * Handles ACTION_DOWN while in the clear or touch interacting states. This event represents the * first finger touching the screen. */ - private void handleActionDown(MotionEvent event, int policyFlags) { + private void handleActionDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mAms.onTouchInteractionStart(); // If we still have not notified the user for the last @@ -432,10 +436,10 @@ public class TouchExplorer extends BaseEventStreamTransformation // The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING final int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); final int pointerIdBits = (1 << pointerId); - mSendHoverEnterAndMoveDelayed.post(event, pointerIdBits, policyFlags); + mSendHoverEnterAndMoveDelayed.post(event, rawEvent, pointerIdBits, policyFlags); } else { // Cache the event until we discern exploration from gesturing. - mSendHoverEnterAndMoveDelayed.addEvent(event); + mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent); } } } @@ -453,7 +457,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case MotionEvent.ACTION_DOWN: // Continue the previous interaction. mSendTouchInteractionEndDelayed.cancel(); - handleActionDown(event, policyFlags); + handleActionDown(event, rawEvent, policyFlags); break; case MotionEvent.ACTION_POINTER_DOWN: handleActionPointerDown(); @@ -462,7 +466,7 @@ public class TouchExplorer extends BaseEventStreamTransformation handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags); break; case MotionEvent.ACTION_UP: - handleActionUp(event, policyFlags); + handleActionUp(event, rawEvent, policyFlags); break; } } @@ -487,7 +491,7 @@ public class TouchExplorer extends BaseEventStreamTransformation handleActionMoveStateTouchExploring(event, rawEvent, policyFlags); break; case MotionEvent.ACTION_UP: - handleActionUp(event, policyFlags); + handleActionUp(event, rawEvent, policyFlags); break; default: break; @@ -520,7 +524,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // figure out what the user is doing. if (mSendHoverEnterAndMoveDelayed.isPending()) { // Cache the event until we discern exploration from gesturing. - mSendHoverEnterAndMoveDelayed.addEvent(event); + mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent); } break; case 2: @@ -538,7 +542,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mDraggingPointerId = pointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags); + event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mState.startDelegating(); @@ -558,13 +562,13 @@ public class TouchExplorer extends BaseEventStreamTransformation * Handles ACTION_UP while in the touch interacting state. This event represents all fingers * being lifted from the screen. */ - private void handleActionUp(MotionEvent event, int policyFlags) { + private void handleActionUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mAms.onTouchInteractionEnd(); final int pointerId = event.getPointerId(event.getActionIndex()); final int pointerIdBits = (1 << pointerId); if (mSendHoverEnterAndMoveDelayed.isPending()) { // If we have not delivered the enter schedule an exit. - mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags); + mSendHoverExitDelayed.post(event, rawEvent, pointerIdBits, policyFlags); } else { // The user is touch exploring so we send events for end. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); @@ -588,7 +592,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // Touch exploration. sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags); mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags); + event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: if (mSendHoverEnterAndMoveDelayed.isPending()) { @@ -638,7 +642,8 @@ public class TouchExplorer extends BaseEventStreamTransformation * @param event The event to be handled. * @param policyFlags The policy flags associated with the event. */ - private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) { + private void handleMotionEventStateDragging( + MotionEvent event, MotionEvent rawEvent, int policyFlags) { int pointerIdBits = 0; // Clear the dragging pointer id if it's no longer valid. if (event.findPointerIndex(mDraggingPointerId) == -1) { @@ -662,7 +667,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mState.startDelegating(); if (mDraggingPointerId != INVALID_POINTER_ID) { mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); + event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); } mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); } break; @@ -681,6 +686,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_MOVE, + rawEvent, pointerIdBits, policyFlags); } else { @@ -690,7 +696,11 @@ public class TouchExplorer extends BaseEventStreamTransformation // Remove move history before send injected non-move events event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. - mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, + mDispatcher.sendMotionEvent( + event, + MotionEvent.ACTION_UP, + rawEvent, + pointerIdBits, policyFlags); // Deliver all pointers to the view hierarchy. mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); @@ -700,7 +710,11 @@ public class TouchExplorer extends BaseEventStreamTransformation mState.startDelegating(); event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. - mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, + mDispatcher.sendMotionEvent( + event, + MotionEvent.ACTION_UP, + rawEvent, + pointerIdBits, policyFlags); // Deliver all pointers to the view hierarchy. mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); @@ -713,7 +727,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mDraggingPointerId = INVALID_POINTER_ID; // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); + event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); } } break; case MotionEvent.ACTION_UP: { @@ -726,7 +740,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mDraggingPointerId = INVALID_POINTER_ID; // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); + event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); } } break; } @@ -738,7 +752,8 @@ public class TouchExplorer extends BaseEventStreamTransformation * @param event The event to be handled. * @param policyFlags The policy flags associated with the event. */ - private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) { + private void handleMotionEventStateDelegating( + MotionEvent event, MotionEvent rawEvent, int policyFlags) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: { Slog.e(LOG_TAG, "Delegating state can only be reached if " @@ -749,7 +764,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case MotionEvent.ACTION_UP: { // Deliver the event. mDispatcher.sendMotionEvent( - event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); + event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags); // Announce the end of a the touch interaction. mAms.onTouchInteractionEnd(); @@ -759,7 +774,7 @@ public class TouchExplorer extends BaseEventStreamTransformation default: { // Deliver the event. mDispatcher.sendMotionEvent( - event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); + event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags); } } } @@ -792,7 +807,11 @@ public class TouchExplorer extends BaseEventStreamTransformation mSendTouchExplorationEndDelayed.post(); } mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags); + event, + MotionEvent.ACTION_HOVER_EXIT, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); } } @@ -807,7 +826,11 @@ public class TouchExplorer extends BaseEventStreamTransformation if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) { final int pointerIdBits = event.getPointerIdBits(); mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags); + event, + MotionEvent.ACTION_HOVER_ENTER, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); } } @@ -891,20 +914,23 @@ public class TouchExplorer extends BaseEventStreamTransformation private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed"; private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>(); + private final List<MotionEvent> mRawEvents = new ArrayList<MotionEvent>(); private int mPointerIdBits; private int mPolicyFlags; - public void post(MotionEvent event, int pointerIdBits, int policyFlags) { + public void post( + MotionEvent event, MotionEvent rawEvent, int pointerIdBits, int policyFlags) { cancel(); - addEvent(event); + addEvent(event, rawEvent); mPointerIdBits = pointerIdBits; mPolicyFlags = policyFlags; mHandler.postDelayed(this, mDetermineUserIntentTimeout); } - public void addEvent(MotionEvent event) { + public void addEvent(MotionEvent event, MotionEvent rawEvent) { mEvents.add(MotionEvent.obtain(event)); + mRawEvents.add(MotionEvent.obtain(rawEvent)); } public void cancel() { @@ -925,6 +951,10 @@ public class TouchExplorer extends BaseEventStreamTransformation for (int i = eventCount - 1; i >= 0; i--) { mEvents.remove(i).recycle(); } + final int rawEventcount = mRawEvents.size(); + for (int i = rawEventcount - 1; i >= 0; i--) { + mRawEvents.remove(i).recycle(); + } } public void forceSendAndRemove() { @@ -939,10 +969,10 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendAccessibilityEvent( AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); - if (!mEvents.isEmpty()) { + if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) { // Deliver a down event. mDispatcher.sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER, - mPointerIdBits, mPolicyFlags); + mRawEvents.get(0), mPointerIdBits, mPolicyFlags); if (DEBUG) { Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: ACTION_HOVER_ENTER"); @@ -952,7 +982,7 @@ public class TouchExplorer extends BaseEventStreamTransformation final int eventCount = mEvents.size(); for (int i = 1; i < eventCount; i++) { mDispatcher.sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE, - mPointerIdBits, mPolicyFlags); + mRawEvents.get(i), mPointerIdBits, mPolicyFlags); if (DEBUG) { Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event: ACTION_HOVER_MOVE"); @@ -970,12 +1000,15 @@ public class TouchExplorer extends BaseEventStreamTransformation private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed"; private MotionEvent mPrototype; + private MotionEvent mRawEvent; private int mPointerIdBits; private int mPolicyFlags; - public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) { + public void post( + MotionEvent prototype, MotionEvent rawEvent, int pointerIdBits, int policyFlags) { cancel(); mPrototype = MotionEvent.obtain(prototype); + mRawEvent = MotionEvent.obtain(rawEvent); mPointerIdBits = pointerIdBits; mPolicyFlags = policyFlags; mHandler.postDelayed(this, mDetermineUserIntentTimeout); @@ -993,8 +1026,14 @@ public class TouchExplorer extends BaseEventStreamTransformation } private void clear() { - mPrototype.recycle(); + if (mPrototype != null) { + mPrototype.recycle(); + } + if (mRawEvent != null) { + mRawEvent.recycle(); + } mPrototype = null; + mRawEvent = null; mPointerIdBits = -1; mPolicyFlags = 0; } @@ -1011,8 +1050,12 @@ public class TouchExplorer extends BaseEventStreamTransformation Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:" + " ACTION_HOVER_EXIT"); } - mDispatcher.sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT, - mPointerIdBits, mPolicyFlags); + mDispatcher.sendMotionEvent( + mPrototype, + MotionEvent.ACTION_HOVER_EXIT, + mRawEvent, + mPointerIdBits, + mPolicyFlags); if (!mSendTouchExplorationEndDelayed.isPending()) { mSendTouchExplorationEndDelayed.cancel(); mSendTouchExplorationEndDelayed.post(); diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java index 49938fa4c6b9..f463260a9d02 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java @@ -71,6 +71,7 @@ public class TouchState { // Helper class to track received pointers. // Todo: collapse or hide this class so multiple classes don't modify it. private final ReceivedPointerTracker mReceivedPointerTracker; + private MotionEvent mLastReceivedEvent; public TouchState() { mReceivedPointerTracker = new ReceivedPointerTracker(); @@ -80,6 +81,10 @@ public class TouchState { public void clear() { setState(STATE_CLEAR); // Reset the pointer trackers. + if (mLastReceivedEvent != null) { + mLastReceivedEvent.recycle(); + mLastReceivedEvent = null; + } mReceivedPointerTracker.clear(); } @@ -89,6 +94,10 @@ public class TouchState { * @param rawEvent The raw touch event. */ public void onReceivedMotionEvent(MotionEvent rawEvent) { + if (mLastReceivedEvent != null) { + mLastReceivedEvent.recycle(); + } + mLastReceivedEvent = MotionEvent.obtain(rawEvent); mReceivedPointerTracker.onMotionEvent(rawEvent); } @@ -216,6 +225,11 @@ public class TouchState { return mReceivedPointerTracker; } + /** @return The last received event. */ + public MotionEvent getLastReceivedEvent() { + return mLastReceivedEvent; + } + /** This class tracks where and when a pointer went down. It does not track its movement. */ class ReceivedPointerTracker { private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker"; @@ -232,8 +246,6 @@ public class TouchState { // or if it goes up the next one that most recently went down. private int mPrimaryPointerId; - // Keep track of the last up pointer data. - private MotionEvent mLastReceivedEvent; ReceivedPointerTracker() { clear(); @@ -254,11 +266,6 @@ public class TouchState { * @param event The event to process. */ public void onMotionEvent(MotionEvent event) { - if (mLastReceivedEvent != null) { - mLastReceivedEvent.recycle(); - } - mLastReceivedEvent = MotionEvent.obtain(event); - final int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: @@ -279,11 +286,6 @@ public class TouchState { } } - /** @return The last received event. */ - public MotionEvent getLastReceivedEvent() { - return mLastReceivedEvent; - } - /** @return The number of received pointers that are down. */ public int getReceivedPointerDownCount() { return Integer.bitCount(mReceivedPointersDown); diff --git a/services/core/Android.bp b/services/core/Android.bp index 80bc1af4d160..4e80977f7d11 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -48,10 +48,12 @@ genrule { ":services.core.protolog.json", ], cmd: "cp $(location :generate-protolog.json) $(out) && " + - "{ diff $(out) $(location :services.core.protolog.json) >/dev/null 2>&1 || " + - "{ echo -e '##### ProtoLog viewer config is stale. ### \nRun: \n " + - "cp $(location :generate-protolog.json) " + - "$(location :services.core.protolog.json)\n' >&2 && false; } }", + "{ ! (diff $(out) $(location :services.core.protolog.json) | grep -q '^<') || " + + "{ echo -e '\\n\\n################################################################\\n#\\n" + + "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" + + "# cp $(location :generate-protolog.json) " + + "$(location :services.core.protolog.json)\\n#\\n" + + "################################################################\\n\\n' >&2 && false; } }", out: ["services.core.protolog.json"], } @@ -106,7 +108,7 @@ 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.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", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 18a8148eb815..9acafaec185e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -495,7 +495,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * arg1 = One of the NETWORK_TESTED_RESULT_* constants. * arg2 = NetID. */ - public static final int EVENT_NETWORK_TESTED = 41; + private static final int EVENT_NETWORK_TESTED = 41; /** * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS @@ -503,7 +503,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * obj = PrivateDnsConfig * arg2 = netid */ - public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42; + private static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42; /** * Request ConnectivityService display provisioning notification. @@ -511,12 +511,12 @@ public class ConnectivityService extends IConnectivityManager.Stub * arg2 = NetID. * obj = Intent to be launched when notification selected by user, null if !arg1. */ - public static final int EVENT_PROVISIONING_NOTIFICATION = 43; + private static final int EVENT_PROVISIONING_NOTIFICATION = 43; /** * This event can handle dismissing notification by given network id. */ - public static final int EVENT_TIMEOUT_NOTIFICATION = 44; + private static final int EVENT_TIMEOUT_NOTIFICATION = 44; /** * Used to specify whether a network should be used even if connectivity is partial. @@ -531,13 +531,13 @@ public class ConnectivityService extends IConnectivityManager.Stub * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. */ - public static final int PROVISIONING_NOTIFICATION_SHOW = 1; + private static final int PROVISIONING_NOTIFICATION_SHOW = 1; /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be hidden. */ - public static final int PROVISIONING_NOTIFICATION_HIDE = 0; + private static final int PROVISIONING_NOTIFICATION_HIDE = 0; private static String eventName(int what) { return sMagicDecoderRing.get(what, Integer.toString(what)); @@ -1938,7 +1938,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - return mPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules, + return NetworkPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules, isNetworkMetered, isBackgroundRestricted); } @@ -2204,7 +2204,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final String iface = networkAgent.linkProperties.getInterfaceName(); final int timeout; - int type = ConnectivityManager.TYPE_NONE; + final int type; if (networkAgent.networkCapabilities.hasTransport( NetworkCapabilities.TRANSPORT_CELLULAR)) { @@ -2219,11 +2219,10 @@ public class ConnectivityService extends IConnectivityManager.Stub 15); type = ConnectivityManager.TYPE_WIFI; } else { - // do not track any other networks - timeout = 0; + return; // do not track any other networks } - if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) { + if (timeout > 0 && iface != null) { try { mNMS.addIdleTimer(iface, timeout, type); } catch (Exception e) { @@ -2299,7 +2298,6 @@ public class ConnectivityService extends IConnectivityManager.Stub @VisibleForTesting protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208"; - private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd"; private void updateTcpBufferSizes(String tcpBufferSizes) { String[] values = null; @@ -2375,7 +2373,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, + @Nullable String[] args) { PriorityDump.dump(mPriorityDumper, fd, writer, args); } @@ -2837,7 +2836,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkMonitorCallbacks(NetworkAgentInfo nai) { mNetId = nai.network.netId; - mNai = new AutodestructReference(nai); + mNai = new AutodestructReference<>(nai); } @Override @@ -4292,7 +4291,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void onChange(boolean selfChange, Uri uri) { final Integer what = mUriEventMap.get(uri); if (what != null) { - mHandler.obtainMessage(what.intValue()).sendToTarget(); + mHandler.obtainMessage(what).sendToTarget(); } else { loge("No matching event to send for URI=" + uri); } @@ -4729,12 +4728,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final String ATTR_MNC = "mnc"; private String getProvisioningUrlBaseFromFile() { - FileReader fileReader = null; - XmlPullParser parser = null; + XmlPullParser parser; Configuration config = mContext.getResources().getConfiguration(); - try { - fileReader = new FileReader(mProvisioningUrlFile); + try (FileReader fileReader = new FileReader(mProvisioningUrlFile)) { parser = Xml.newPullParser(); parser.setInput(fileReader); XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); @@ -4769,12 +4766,6 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); } catch (IOException e) { loge("I/O exception reading Carrier Provisioning Urls file: " + e); - } finally { - if (fileReader != null) { - try { - fileReader.close(); - } catch (IOException e) {} - } } return null; } @@ -5104,8 +5095,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - // This checks that the passed capabilities either do not request a specific SSID/SignalStrength - // , or the calling app has permission to do so. + // This checks that the passed capabilities either do not request a + // specific SSID/SignalStrength, or the calling app has permission to do so. private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc, int callerPid, int callerUid) { if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) { @@ -5238,7 +5229,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final int uid = Binder.getCallingUid(); Integer uidReqs = mBandwidthRequests.get(uid); if (uidReqs == null) { - uidReqs = new Integer(0); + uidReqs = 0; } mBandwidthRequests.put(uid, ++uidReqs); } @@ -5572,7 +5563,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp, - LinkProperties oldLp) { + @NonNull LinkProperties oldLp) { int netId = networkAgent.network.netId; // The NetworkAgentInfo does not know whether clatd is running on its network or not, or @@ -5687,7 +5678,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) { // Compare the route diff to determine which routes should be added and removed. - CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>( + CompareResult<RouteInfo> routeDiff = new CompareResult<>( oldLp != null ? oldLp.getAllRoutes() : null, newLp != null ? newLp.getAllRoutes() : null); @@ -5706,7 +5697,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } for (RouteInfo route : routeDiff.added) { - if (route.hasGateway() == false) continue; + if (!route.hasGateway()) continue; if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId); try { mNMS.addRoute(netId, route); @@ -5935,8 +5926,8 @@ public class ConnectivityService extends IConnectivityManager.Stub * 3. the VPN is fully-routed * 4. the VPN interface is non-null * - * @See INetd#firewallAddUidInterfaceRules - * @See INetd#firewallRemoveUidInterfaceRules + * @see INetd#firewallAddUidInterfaceRules + * @see INetd#firewallRemoveUidInterfaceRules */ private boolean requiresVpnIsolation(@NonNull NetworkAgentInfo nai, NetworkCapabilities nc, LinkProperties lp) { @@ -7051,9 +7042,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ShellCallback callback, - ResultReceiver resultReceiver) { + public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, + FileDescriptor err, @NonNull String[] args, ShellCallback callback, + @NonNull ResultReceiver resultReceiver) { (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver); } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 2fcb7faabc3a..35a06a977a58 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -2499,13 +2499,6 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, "Access Fine Location permission not granted to inject Location"); - if (location == null) { - if (D) { - Log.d(TAG, "injectLocation(): called with null location"); - } - return false; - } - synchronized (mLock) { LocationProvider provider = getLocationProviderLocked(location.getProvider()); if (provider == null || !provider.isUseableLocked()) { @@ -2708,9 +2701,6 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public ProviderProperties getProviderProperties(String providerName) { synchronized (mLock) { - checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(), - providerName); - LocationProvider provider = getLocationProviderLocked(providerName); if (provider == null) { return null; diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c01ccba90ac2..f91cf0cc1255 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -385,7 +385,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext = context; mBatteryStats = BatteryStatsService.getService(); - int numPhones = TelephonyManager.getDefault().getPhoneCount(); + int numPhones = TelephonyManager.getDefault().getMaxPhoneCount(); if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones); mNumPhones = numPhones; mCallState = new int[numPhones]; diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 9936d73fb800..d622fb433ed8 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -29,6 +29,7 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.input.InputManager; 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; @@ -108,6 +109,9 @@ public class VibratorService extends IVibratorService.Stub // If a vibration is playing for longer than 5s, it's probably not haptic feedback. private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; + // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration. + private static final long ASYNC_TIMEOUT_MULTIPLIER = 2; + // A mapping from the intensity adjustment to the scaling to apply, where the intensity // adjustment is defined as the delta between the default intensity level and the user selected @@ -123,6 +127,7 @@ public class VibratorService extends IVibratorService.Stub private final boolean mAllowPriorityVibrationsInLowPowerMode; private final boolean mSupportsAmplitudeControl; private final boolean mSupportsExternalControl; + private final long mCapabilities; private final int mDefaultVibrationAmplitude; private final SparseArray<VibrationEffect> mFallbackEffects; private final SparseArray<Integer> mProcStatesCache = new SparseArray(); @@ -163,9 +168,10 @@ public class VibratorService extends IVibratorService.Stub static native void vibratorOff(); static native boolean vibratorSupportsAmplitudeControl(); static native void vibratorSetAmplitude(int amplitude); - static native long vibratorPerformEffect(long effect, long strength); + static native long vibratorPerformEffect(long effect, long strength, Vibration vibration); static native boolean vibratorSupportsExternalControl(); static native void vibratorSetExternalControl(boolean enabled); + static native long vibratorGetCapabilities(); private final IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { @@ -226,6 +232,14 @@ public class VibratorService extends IVibratorService.Stub } } + private void onComplete() { + synchronized (mLock) { + if (this == mCurrentVibration) { + doCancelVibrateLocked(); + } + } + } + public boolean hasTimeoutLongerThan(long millis) { final long duration = effect.getDuration(); return duration >= 0 && duration > millis; @@ -347,6 +361,7 @@ public class VibratorService extends IVibratorService.Stub mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl(); mSupportsExternalControl = vibratorSupportsExternalControl(); + mCapabilities = vibratorGetCapabilities(); mContext = context; PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); @@ -1135,10 +1150,14 @@ public class VibratorService extends IVibratorService.Stub } // Input devices don't support prebaked effect, so skip trying it with them. if (!usingInputDeviceVibrators) { - long timeout = vibratorPerformEffect(prebaked.getId(), - prebaked.getEffectStrength()); + long duration = vibratorPerformEffect(prebaked.getId(), + prebaked.getEffectStrength(), vib); + long timeout = duration; + if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) { + timeout *= ASYNC_TIMEOUT_MULTIPLIER; + } if (timeout > 0) { - noteVibratorOnLocked(vib.uid, timeout); + noteVibratorOnLocked(vib.uid, duration); return timeout; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 71ff60720489..ee98af4020ad 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7441,6 +7441,7 @@ public class ActivityManagerService extends IActivityManager.Stub dst.setProcess(r); dst.notifyAll(); } + dst.mRestartCount = 0; updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority); @@ -13884,9 +13885,20 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } + /** + * Remove the dying provider from known provider map and launching provider map. + * @param proc The dying process recoder + * @param cpr The provider to be removed. + * @param always If true, remove the provider from launching map always, no more restart attempt + * @return true if the given provider is in launching + */ private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) { - final boolean inLaunching = mLaunchingProviders.contains(cpr); + boolean inLaunching = mLaunchingProviders.contains(cpr); + if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) { + // It's being launched but we've reached maximum attempts, force the removal + always = true; + } if (!inLaunching || always) { synchronized (cpr) { @@ -13938,6 +13950,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (inLaunching && always) { mLaunchingProviders.remove(cpr); + cpr.mRestartCount = 0; + inLaunching = false; } return inLaunching; } @@ -14153,6 +14167,10 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) { ContentProviderRecord cpr = mLaunchingProviders.get(i); if (cpr.launchingApp == app) { + if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) { + // It's being launched but we've reached maximum attempts, mark it as bad + alwaysBad = true; + } if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) { restart = true; } else { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 058afd3b4d68..8be2438b4f2f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2859,7 +2859,21 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - private int runCompat(PrintWriter pw) { + private void killPackage(String packageName, PrintWriter pw) throws RemoteException { + int uid = mPm.getPackageUid(packageName, 0, mUserId); + if (uid < 0) { + // uid is negative if the package wasn't found. + pw.println("Didn't find package " + packageName + " on device."); + } else { + pw.println("Killing package " + packageName + " (UID " + uid + ")."); + final long origId = Binder.clearCallingIdentity(); + mInterface.killUid(UserHandle.getAppId(uid), + UserHandle.USER_ALL, "killPackage"); + Binder.restoreCallingIdentity(origId); + } + } + + private int runCompat(PrintWriter pw) throws RemoteException { final CompatConfig config = CompatConfig.get(); String toggleValue = getNextArgRequired(); long changeId; @@ -2873,13 +2887,14 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println("Unknown or invalid change: '" + changeIdString + "'."); } String packageName = getNextArgRequired(); - switch(toggleValue) { + switch (toggleValue) { case "enable": if (!config.addOverride(changeId, packageName, true)) { pw.println("Warning! Change " + changeId + " is not known yet. Enabling it" + " could have no effect."); } pw.println("Enabled change " + changeId + " for " + packageName + "."); + killPackage(packageName, pw); return 0; case "disable": if (!config.addOverride(changeId, packageName, false)) { @@ -2887,11 +2902,13 @@ final class ActivityManagerShellCommand extends ShellCommand { + " could have no effect."); } pw.println("Disabled change " + changeId + " for " + packageName + "."); + killPackage(packageName, pw); return 0; case "reset": if (config.removeOverride(changeId, packageName)) { pw.println("Reset change " + changeId + " for " + packageName + " to default value."); + killPackage(packageName, pw); } else { pw.println("No override exists for changeId " + changeId + "."); } @@ -3210,6 +3227,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Write all pending state to storage."); pw.println(" compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>"); pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>."); + pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect)."); pw.println(); Intent.printIntentArgsHelp(pw, ""); } diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index 46dfc7c60fd9..d8d8cccc05f3 100644 --- a/services/core/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java @@ -38,6 +38,9 @@ import java.io.PrintWriter; import java.util.ArrayList; final class ContentProviderRecord implements ComponentName.WithComponentName { + // Maximum attempts to bring up the content provider before giving up. + static final int MAX_RETRY_COUNT = 3; + final ActivityManagerService service; public final ProviderInfo info; final int uid; @@ -54,6 +57,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; // Count for external process for which we have no handles. int externalProcessNoHandleCount; + int mRestartCount; // number of times we tried before bringing up it successfully. ProcessRecord proc; // if non-null, hosting process. ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. String stringName; diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 5c8e530faf70..8e4474c462ab 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -133,12 +133,12 @@ class UserController implements Handler.Callback { static final int CONTINUE_USER_SWITCH_MSG = 20; static final int USER_SWITCH_TIMEOUT_MSG = 30; static final int START_PROFILES_MSG = 40; - static final int SYSTEM_USER_START_MSG = 50; - static final int SYSTEM_USER_CURRENT_MSG = 60; + static final int USER_START_MSG = 50; + static final int USER_CURRENT_MSG = 60; static final int FOREGROUND_PROFILE_CHANGED_MSG = 70; static final int REPORT_USER_SWITCH_COMPLETE_MSG = 80; static final int USER_SWITCH_CALLBACKS_TIMEOUT_MSG = 90; - static final int SYSTEM_USER_UNLOCK_MSG = 100; + static final int USER_UNLOCK_MSG = 100; static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 110; static final int START_USER_SWITCH_FG_MSG = 120; @@ -368,16 +368,18 @@ class UserController implements Handler.Callback { } } - mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG, - userId, 0)); - Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mInjector.broadcastIntent(intent, null, resultTo, 0, null, null, - new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, - AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, - Binder.getCallingUid(), Binder.getCallingPid(), userId); + if (!mInjector.getUserManager().isPreCreated(userId)) { + mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG, + userId, 0)); + Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + mInjector.broadcastIntent(intent, null, resultTo, 0, null, null, + new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, + Binder.getCallingUid(), Binder.getCallingPid(), userId); + } } // We need to delay unlocking managed profiles until the parent user @@ -438,8 +440,7 @@ class UserController implements Handler.Callback { // Dispatch unlocked to system services; when fully dispatched, // that calls through to the next "unlocked" phase - mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) - .sendToTarget(); + mHandler.obtainMessage(USER_UNLOCK_MSG, userId, 0, uss).sendToTarget(); }); return true; } @@ -555,6 +556,17 @@ class UserController implements Handler.Callback { } } + if (userInfo.preCreated) { + Slog.i(TAG, "Stopping pre-created user " + userInfo.toFullString()); + // Pre-created user was started right after creation so services could properly + // intialize it; it should be stopped right away as it's not really a "real" user. + // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback + // on SystemService instead. + stopUser(userInfo.id, /* force= */ true, /* stopUserCallback= */ null, + /* keyEvictedCallback= */ null); + return; + } + // Spin up app widgets prior to boot-complete, so they can be ready promptly mInjector.startUserWidgets(userId); @@ -799,7 +811,8 @@ class UserController implements Handler.Callback { mInjector.systemServiceManagerCleanupUser(userId); mInjector.stackSupervisorRemoveUser(userId); // Remove the user if it is ephemeral. - if (getUserInfo(userId).isEphemeral()) { + UserInfo userInfo = getUserInfo(userId); + if (userInfo.isEphemeral() && !userInfo.preCreated) { mInjector.getUserManager().removeUserEvenWhenDisallowed(userId); } @@ -1069,6 +1082,11 @@ class UserController implements Handler.Callback { return false; } + if (foreground && userInfo.preCreated) { + Slog.w(TAG, "Cannot start pre-created user #" + userId + " as foreground"); + return false; + } + if (foreground && mUserSwitchUiEnabled) { t.traceBegin("startFreezingScreen"); mInjector.getWindowManager().startFreezingScreen( @@ -1178,15 +1196,13 @@ class UserController implements Handler.Callback { // Booting up a new user, need to tell system services about it. // Note that this is on the same handler as scheduling of broadcasts, // which is important because it needs to go first. - mHandler.sendMessage( - mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0)); + mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, 0)); t.traceEnd(); } t.traceBegin("sendMessages"); if (foreground) { - mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId, - oldUserId)); + mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId)); mHandler.removeMessages(REPORT_USER_SWITCH_MSG); mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG, @@ -1195,6 +1211,10 @@ class UserController implements Handler.Callback { oldUserId, userId, uss), USER_SWITCH_TIMEOUT_MS); } + if (userInfo.preCreated) { + needStart = false; + } + if (needStart) { // Send USER_STARTED broadcast Intent intent = new Intent(Intent.ACTION_USER_STARTED); @@ -2168,14 +2188,14 @@ class UserController implements Handler.Callback { case START_PROFILES_MSG: startProfiles(); break; - case SYSTEM_USER_START_MSG: + case USER_START_MSG: mInjector.batteryStatsServiceNoteEvent( BatteryStats.HistoryItem.EVENT_USER_RUNNING_START, Integer.toString(msg.arg1), msg.arg1); mInjector.getSystemServiceManager().startUser(TimingsTraceAndSlog.newAsyncLog(), msg.arg1); break; - case SYSTEM_USER_UNLOCK_MSG: + case USER_UNLOCK_MSG: final int userId = msg.arg1; mInjector.getSystemServiceManager().unlockUser(userId); // Loads recents on a worker thread that allows disk I/O @@ -2184,7 +2204,7 @@ class UserController implements Handler.Callback { }); finishUserUnlocked((UserState) msg.obj); break; - case SYSTEM_USER_CURRENT_MSG: + case USER_CURRENT_MSG: mInjector.batteryStatsServiceNoteEvent( BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH, Integer.toString(msg.arg2), msg.arg2); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index ccbe08f475c3..a6ac17dc9b6a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -59,6 +59,7 @@ import android.hardware.hdmi.HdmiAudioSystemClient; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiTvClient; +import android.hardware.input.InputManager; import android.hardware.usb.UsbManager; import android.media.AudioAttributes; import android.media.AudioFocusInfo; @@ -545,6 +546,10 @@ public class AudioService extends IAudioService.Stub private String mEnabledSurroundFormats; private boolean mSurroundModeChanged; + private boolean mMicMuteFromSwitch; + private boolean mMicMuteFromApi; + private boolean mMicMuteFromRestrictions; + @GuardedBy("mSettingsLock") private int mAssistantUid; @@ -882,6 +887,8 @@ public class AudioService extends IAudioService.Stub mRoleObserver.register(); onIndicateSystemReady(); + + setMicMuteFromSwitchInput(); } RoleObserver mRoleObserver; @@ -1021,6 +1028,8 @@ public class AudioService extends IAudioService.Stub sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); + + setMicMuteFromSwitchInput(); } private void onDispatchAudioServerStateChange(boolean state) { @@ -1557,12 +1566,13 @@ public class AudioService extends IAudioService.Stub AudioSystem.setMasterMute(masterMute); broadcastMasterMuteStatus(masterMute); - boolean microphoneMute = mUserManagerInternal.getUserRestriction( + mMicMuteFromRestrictions = mUserManagerInternal.getUserRestriction( currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE); if (DEBUG_VOL) { - Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser)); + Log.d(TAG, String.format("Mic mute %b, user=%d", mMicMuteFromRestrictions, + currentUser)); } - AudioSystem.muteMicrophone(microphoneMute); + setMicrophoneMuteNoCallerCheck(currentUser); } private int rescaleIndex(int index, int srcStream, int dstStream) { @@ -2837,20 +2847,45 @@ public class AudioService extends IAudioService.Stub != PackageManager.PERMISSION_GRANTED) { return; } - setMicrophoneMuteNoCallerCheck(on, userId); + mMicMuteFromApi = on; + setMicrophoneMuteNoCallerCheck(userId); + } + + /** @see AudioManager#setMicrophoneMuteFromSwitch(boolean) */ + public void setMicrophoneMuteFromSwitch(boolean on) { + int userId = Binder.getCallingUid(); + if (userId != android.os.Process.SYSTEM_UID) { + Log.e(TAG, "setMicrophoneMuteFromSwitch() called from non system user!"); + return; + } + mMicMuteFromSwitch = on; + setMicrophoneMuteNoCallerCheck(userId); + } + + private void setMicMuteFromSwitchInput() { + InputManager im = mContext.getSystemService(InputManager.class); + final int isMicMuted = im.isMicMuted(); + if (isMicMuted != InputManager.SWITCH_STATE_UNKNOWN) { + setMicrophoneMuteFromSwitch(im.isMicMuted() != InputManager.SWITCH_STATE_OFF); + } + } + + public boolean isMicrophoneMuted() { + return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi; } - private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) { + private void setMicrophoneMuteNoCallerCheck(int userId) { + final boolean muted = isMicrophoneMuted(); if (DEBUG_VOL) { - Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId)); + Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId)); } // only mute for the current user - if (getCurrentUserId() == userId) { + if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); - AudioSystem.muteMicrophone(on); + AudioSystem.muteMicrophone(muted); Binder.restoreCallingIdentity(identity); - if (on != currentMute) { + if (muted != currentMute) { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); @@ -5390,7 +5425,8 @@ public class AudioService extends IAudioService.Stub final boolean isRestricted = newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE); if (wasRestricted != isRestricted) { - setMicrophoneMuteNoCallerCheck(isRestricted, userId); + mMicMuteFromRestrictions = isRestricted; + setMicrophoneMuteNoCallerCheck(userId); } } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 7302b985181b..3d341ef67d6f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -25,7 +25,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; import android.app.ActivityManager; -import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.KeyguardManager; import android.app.UserSwitchObserver; @@ -257,12 +256,11 @@ public class BiometricService extends SystemService { private final Injector mInjector; @VisibleForTesting final IBiometricService.Stub mImpl; - private final AppOpsManager mAppOps; private final boolean mHasFeatureFingerprint; private final boolean mHasFeatureIris; private final boolean mHasFeatureFace; @VisibleForTesting - SettingObserver mSettingObserver; + final SettingObserver mSettingObserver; private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; private final Random mRandom = new Random(); @@ -411,8 +409,8 @@ public class BiometricService extends SystemService { }; private final class Authenticator { - int mType; - BiometricAuthenticator mAuthenticator; + final int mType; + final BiometricAuthenticator mAuthenticator; Authenticator(int type, BiometricAuthenticator authenticator) { mType = type; @@ -445,9 +443,9 @@ public class BiometricService extends SystemService { private final ContentResolver mContentResolver; private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks; - private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>(); - private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>(); - private Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>(); + private final Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>(); + private final Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>(); + private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>(); /** * Creates a content observer. @@ -864,14 +862,6 @@ public class BiometricService extends SystemService { } } - private void checkAppOp(String opPackageName, int callingUid) { - if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, callingUid, - opPackageName) != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied"); - throw new SecurityException("Permission denied"); - } - } - private void checkInternalPermission() { getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL, "Must have USE_BIOMETRIC_INTERNAL permission"); @@ -942,7 +932,6 @@ public class BiometricService extends SystemService { mInjector = injector; mImpl = new BiometricServiceWrapper(); - mAppOps = context.getSystemService(AppOpsManager.class); mEnabledOnKeyguardCallbacks = new ArrayList<>(); mSettingObserver = mInjector.getSettingObserver(context, mHandler, mEnabledOnKeyguardCallbacks); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 8e09d0e5958e..852b26d1ff07 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -47,7 +47,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public void reportChange(long changeId, ApplicationInfo appInfo) { - reportChange(changeId, appInfo, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + reportChange(changeId, appInfo.uid, + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); } @Override @@ -60,13 +61,18 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void reportChangeByUid(long changeId, int uid) { + reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + } + + @Override public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) { if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) { - reportChange(changeId, appInfo, + reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); return true; } - reportChange(changeId, appInfo, + reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED); return false; } @@ -81,6 +87,19 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public boolean isChangeEnabledByUid(long changeId, int uid) { + String[] packages = mContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + return true; + } + boolean enabled = true; + for (String packageName : packages) { + enabled = enabled && isChangeEnabledByPackageName(changeId, packageName); + } + return enabled; + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; CompatConfig.get().dumpConfig(pw); @@ -95,8 +114,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { return null; } - private void reportChange(long changeId, ApplicationInfo appInfo, int state) { - int uid = appInfo.uid; + private void reportChange(long changeId, int uid, int state) { mChangeReporter.reportChange(uid, changeId, state); } } diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 66bd27c1a76b..aea6d8d24312 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -16,6 +16,7 @@ package com.android.server.connectivity; +import android.annotation.NonNull; import android.net.ConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; @@ -325,13 +326,13 @@ public class Nat464Xlat extends BaseNetworkObserver { * This is necessary because the LinkProperties in mNetwork come from the transport layer, which * has no idea that 464xlat is running on top of it. */ - public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) { + public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) { lp.setNat64Prefix(mNat64Prefix); if (!isRunning()) { return; } - if (lp == null || lp.getAllInterfaceNames().contains(mIface)) { + if (lp.getAllInterfaceNames().contains(mIface)) { return; } @@ -434,7 +435,7 @@ public class Nat464Xlat extends BaseNetworkObserver { @Override public void interfaceRemoved(String iface) { - mNetwork.handler().post(() -> { handleInterfaceRemoved(iface); }); + mNetwork.handler().post(() -> handleInterfaceRemoved(iface)); } @Override diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 7b3eae14c97a..6b70e5f00330 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -199,13 +199,22 @@ public class Vpn { */ private @NonNull List<String> mLockdownWhitelist = Collections.emptyList(); - /** - * List of UIDs for which networking should be blocked until VPN is ready, during brief periods - * when VPN is not running. For example, during system startup or after a crash. + /** + * A memory of what UIDs this class told netd to block for the lockdown feature. + * + * Netd maintains ranges of UIDs for which network should be restricted to using only the VPN + * for the lockdown feature. This class manages these UIDs and sends this information to netd. + * To avoid sending the same commands multiple times (which would be wasteful) and to be able + * to revoke lists (when the rules should change), it's simplest to keep this cache of what + * netd knows, so it can be diffed and sent most efficiently. + * + * The contents of this list must only be changed when updating the UIDs lists with netd, + * since it needs to keep in sync with the picture netd has of them. + * * @see mLockdown */ @GuardedBy("this") - private Set<UidRange> mBlockedUsers = new ArraySet<>(); + private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>(); // Handle of the user initiating VPN. private final int mUserHandle; @@ -254,7 +263,7 @@ public class Vpn { } /** - * Update current state, dispaching event to listeners. + * Update current state, dispatching event to listeners. */ @VisibleForTesting protected void updateState(DetailedState detailedState, String reason) { @@ -1325,7 +1334,7 @@ public class Vpn { * {@link Vpn} goes through a VPN connection or is blocked until one is * available, {@code false} to lift the requirement. * - * @see #mBlockedUsers + * @see #mBlockedUidsAsToldToNetd */ @GuardedBy("this") private void setVpnForcedLocked(boolean enforce) { @@ -1336,37 +1345,47 @@ public class Vpn { exemptedPackages = new ArrayList<>(mLockdownWhitelist); exemptedPackages.add(mPackage); } - final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers); + final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd); - Set<UidRange> addedRanges = Collections.emptySet(); + final Set<UidRange> rangesToTellNetdToAdd; if (enforce) { - addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle, - /* allowedApplications */ null, - /* disallowedApplications */ exemptedPackages); + final Set<UidRange> rangesThatShouldBeBlocked = + createUserAndRestrictedProfilesRanges(mUserHandle, + /* allowedApplications */ null, + /* disallowedApplications */ exemptedPackages); // The UID range of the first user (0-99999) would block the IPSec traffic, which comes // directly from the kernel and is marked as uid=0. So we adjust the range to allow // it through (b/69873852). - for (UidRange range : addedRanges) { + for (UidRange range : rangesThatShouldBeBlocked) { if (range.start == 0) { - addedRanges.remove(range); + rangesThatShouldBeBlocked.remove(range); if (range.stop != 0) { - addedRanges.add(new UidRange(1, range.stop)); + rangesThatShouldBeBlocked.add(new UidRange(1, range.stop)); } } } - removedRanges.removeAll(addedRanges); - addedRanges.removeAll(mBlockedUsers); + rangesToTellNetdToRemove.removeAll(rangesThatShouldBeBlocked); + rangesToTellNetdToAdd = rangesThatShouldBeBlocked; + // The ranges to tell netd to add are the ones that should be blocked minus the + // ones it already knows to block. Note that this will change the contents of + // rangesThatShouldBeBlocked, but the list of ranges that should be blocked is + // not used after this so it's fine to destroy it. + rangesToTellNetdToAdd.removeAll(mBlockedUidsAsToldToNetd); + } else { + rangesToTellNetdToAdd = Collections.emptySet(); } - setAllowOnlyVpnForUids(false, removedRanges); - setAllowOnlyVpnForUids(true, addedRanges); + // If mBlockedUidsAsToldToNetd used to be empty, this will always be a no-op. + setAllowOnlyVpnForUids(false, rangesToTellNetdToRemove); + // If nothing should be blocked now, this will now be a no-op. + setAllowOnlyVpnForUids(true, rangesToTellNetdToAdd); } /** - * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed - * to make connections through sockets that have had {@code protect()} called on them. + * Tell netd to add or remove a list of {@link UidRange}s to the list of UIDs that are only + * allowed to make connections through sockets that have had {@code protect()} called on them. * * @param enforce {@code true} to add to the blacklist, {@code false} to remove. * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is @@ -1388,9 +1407,9 @@ public class Vpn { return false; } if (enforce) { - mBlockedUsers.addAll(ranges); + mBlockedUidsAsToldToNetd.addAll(ranges); } else { - mBlockedUsers.removeAll(ranges); + mBlockedUidsAsToldToNetd.removeAll(ranges); } return true; } @@ -1557,17 +1576,18 @@ public class Vpn { /** * @param uid The target uid. * - * @return {@code true} if {@code uid} is included in one of the mBlockedUsers ranges and the - * VPN is not connected, or if the VPN is connected but does not apply to the {@code uid}. + * @return {@code true} if {@code uid} is included in one of the mBlockedUidsAsToldToNetd + * ranges and the VPN is not connected, or if the VPN is connected but does not apply to + * the {@code uid}. * * @apiNote This method don't check VPN lockdown status. - * @see #mBlockedUsers + * @see #mBlockedUidsAsToldToNetd */ public synchronized boolean isBlockingUid(int uid) { if (mNetworkInfo.isConnected()) { return !appliesToUid(uid); } else { - return UidRange.containsUid(mBlockedUsers, uid); + return UidRange.containsUid(mBlockedUidsAsToldToNetd, uid); } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 8fbad4c5910b..7e6e6680905e 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -47,6 +47,7 @@ import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; import android.hardware.input.KeyboardLayout; import android.hardware.input.TouchCalibration; +import android.media.AudioManager; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -296,6 +297,9 @@ public class InputManagerService extends IInputManager.Stub /** Switch code: Camera lens cover. When set the lens is covered. */ public static final int SW_CAMERA_LENS_COVER = 0x09; + /** Switch code: Microphone. When set it is off. */ + public static final int SW_MUTE_DEVICE = 0x0e; + public static final int SW_LID_BIT = 1 << SW_LID; public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE; public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; @@ -306,6 +310,7 @@ public class InputManagerService extends IInputManager.Stub public static final int SW_JACK_BITS = SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT; public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER; + public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE; /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; @@ -972,6 +977,11 @@ public class InputManagerService extends IInputManager.Stub } @Override // Binder call + public int isMicMuted() { + return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE); + } + + @Override // Binder call public void registerTabletModeChangedListener(ITabletModeChangedListener listener) { if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, "registerTabletModeChangedListener()")) { @@ -1804,6 +1814,12 @@ public class InputManagerService extends IInputManager.Stub mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, args).sendToTarget(); } + + if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) { + final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0); + AudioManager audioManager = mContext.getSystemService(AudioManager.class); + audioManager.setMicrophoneMuteFromSwitch(micMute); + } } // Native callback. diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING new file mode 100644 index 000000000000..b45b4eaa1ba7 --- /dev/null +++ b/services/core/java/com/android/server/integrity/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.integrity." + }, + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java new file mode 100644 index 000000000000..fc4430640b90 --- /dev/null +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java @@ -0,0 +1,55 @@ +/* + * 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.integrity.engine; + +import com.android.server.integrity.model.Rule; + +import java.util.ArrayList; +import java.util.List; + +/** + * The engine used to evaluate rules against app installs. + * + * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine + * to allow/block that install. + */ +public final class RuleEvaluationEngine { + private static final String TAG = "RuleEvaluation"; + + // The engine for loading rules, retrieving metadata for app installs, and evaluating app + // installs against rules. + private static RuleEvaluationEngine sRuleEvaluationEngine; + + // The subset of rules loaded to be used to evaluate an app install request. + // TODO: Load rules relevant to app installs. + private List<Rule> mRules; + + private RuleEvaluationEngine() { + // Initialize rules with the empty rule set. + mRules = new ArrayList<>(); + } + + /** + * Provide a singleton instance of the rule evaluation engine. + */ + public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() { + if (sRuleEvaluationEngine == null) { + return new RuleEvaluationEngine(); + } + return sRuleEvaluationEngine; + } +} diff --git a/services/core/java/com/android/server/integrity/engine/RuleLoader.java b/services/core/java/com/android/server/integrity/engine/RuleLoader.java new file mode 100644 index 000000000000..af24d7a21dc8 --- /dev/null +++ b/services/core/java/com/android/server/integrity/engine/RuleLoader.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 com.android.server.integrity.engine; + +import com.android.server.integrity.model.Rule; + +import java.util.ArrayList; +import java.util.List; + +/** + * A helper class for loading rules to the rule evaluation engine. + * + * <p>Expose fine-grained APIs for loading rules to be passed to the rule evaluation engine. + * + * <p>It supports: + * <ul> + * <li>Loading rules based on some keys, such as PACKAGE_NAME and APP_CERT.</li> + * </ul> + * + * <p>It does NOT support: + * <ul> + * <li>Loading the list of all rules.</li> + * <li>Merging rules resulting from different APIs.</li> + * </ul> + */ +final class RuleLoader { + + List<Rule> loadRulesByPackageName(String packageName) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByAppCertificate(String appCertificate) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByInstallerName(String installerName) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByInstallerCertificate(String installerCertificate) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } +} diff --git a/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java index c2ed3df0ffff..814b8e1d783b 100644 --- a/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java +++ b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.integrity.engine; +package com.android.server.integrity.model; /** * The app install metadata. @@ -32,7 +32,7 @@ public final class AppInstallMetadata { final int mVersionCode; final boolean mIsPreInstalled; - AppInstallMetadata(String packageName, String appCertificate, String installerName, + public AppInstallMetadata(String packageName, String appCertificate, String installerName, String installerCertificate, int versionCode, boolean isPreInstalled) { this.mPackageName = packageName; this.mAppCertificate = appCertificate; diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java new file mode 100644 index 000000000000..a6e08d8504ed --- /dev/null +++ b/services/core/java/com/android/server/integrity/model/Rule.java @@ -0,0 +1,160 @@ +/* + * 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.integrity.model; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; + +/** + * Represent rules to be used in the rule evaluation engine to match against app installs. + * + * <p>Instances of this class are immutable. + */ +public final class Rule { + + // Holds an empty rule instance. + public static final Rule EMPTY = new Rule(); + + enum Key { + PACKAGE_NAME, + APP_CERTIFICATE, + INSTALLER_NAME, + INSTALLER_CERTIFICATE, + VERSION_CODE, + PRE_INSTALLED + } + + enum Effect { + DENY + } + + enum Operator { + EQ, + LT, + LE, + GT, + GE + } + + enum Connector { + AND, + OR, + NOT + } + + private final Formula mFormula; + private final Effect mEffect; + + private Rule() { + this.mFormula = null; + this.mEffect = null; + } + + public Rule(Formula formula, Effect effect) { + this.mFormula = checkNotNull(formula); + this.mEffect = checkNotNull(effect); + } + + /** + * Indicates whether the rule is empty or not. + * + * @return {@code true} if the rule is empty, and {@code false} otherwise. + */ + public boolean isEmpty() { + return mFormula == null && mEffect == null; + } + + public Formula getFormula() { + return mFormula; + } + + public Effect getEffect() { + return mEffect; + } + + // TODO: Consider moving the sub-components to their respective model class. + + /** + * Represents a rule logic/content. + */ + abstract static class Formula { + + } + + /** + * Represents a simple formula consisting of an app install metadata field and a value. + */ + public static final class AtomicFormula extends Formula { + + final Key mKey; + final Operator mOperator; + + // The value of a key can take either 1 of 3 forms: String, Integer, or Boolean. + // It cannot have multiple values. + @Nullable + final String mStringValue; + @Nullable + final Integer mIntValue; + @Nullable + final Boolean mBoolValue; + + public AtomicFormula(Key key, Operator operator, String stringValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = stringValue; + this.mIntValue = null; + this.mBoolValue = null; + } + + public AtomicFormula(Key key, Operator operator, Integer intValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = null; + this.mIntValue = intValue; + this.mBoolValue = null; + } + + public AtomicFormula(Key key, Operator operator, Boolean boolValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = null; + this.mIntValue = null; + this.mBoolValue = boolValue; + } + } + + /** + * Represents a complex formula consisting of other simple and complex formulas. + */ + public static final class OpenFormula extends Formula { + + final Connector mConnector; + final Formula mMainFormula; + final Formula mAuxiliaryFormula; + + public OpenFormula(Connector connector, Formula mainFormula, + @Nullable Formula auxiliaryFormula) { + this.mConnector = checkNotNull(connector); + this.mMainFormula = checkNotNull(mainFormula); + this.mAuxiliaryFormula = auxiliaryFormula; + } + } +} diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 378d9ebdaaa8..bad484fa3807 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -61,7 +61,10 @@ import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; import android.hardware.authsecret.V1_0.IAuthSecret; import android.hardware.biometrics.BiometricManager; +import android.hardware.face.Face; import android.hardware.face.FaceManager; +import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintManager; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -117,6 +120,7 @@ import com.android.internal.widget.LockPatternUtils.CredentialType; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.LocalServices; +import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.locksettings.LockSettingsStorage.CredentialHash; import com.android.server.locksettings.LockSettingsStorage.PersistentData; @@ -387,8 +391,15 @@ public class LockSettingsService extends ILockSettings.Stub { return mContext; } - public Handler getHandler() { - return new Handler(); + public ServiceThread getServiceThread() { + ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /*allowIo*/); + handlerThread.start(); + return handlerThread; + } + + public Handler getHandler(ServiceThread handlerThread) { + return new Handler(handlerThread.getLooper()); } public LockSettingsStorage getStorage() { @@ -483,6 +494,23 @@ public class LockSettingsService extends ILockSettings.Stub { public boolean isGsiRunning() { return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0; } + + public FingerprintManager getFingerprintManager() { + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + return (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE); + } else { + return null; + } + } + + public FaceManager getFaceManager() { + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { + return (FaceManager) mContext.getSystemService(Context.FACE_SERVICE); + } else { + return null; + } + } + } public LockSettingsService(Context context) { @@ -495,7 +523,7 @@ public class LockSettingsService extends ILockSettings.Stub { mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore); - mHandler = injector.getHandler(); + mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); mActivityManager = injector.getActivityManager(); @@ -2713,6 +2741,7 @@ public class LockSettingsService extends ILockSettings.Stub { fixateNewestUserKeyAuth(userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); + removeBiometricsForUser(userId); } setSyntheticPasswordHandleLocked(newHandle, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); @@ -2728,6 +2757,85 @@ public class LockSettingsService extends ILockSettings.Stub { return newHandle; } + private void removeBiometricsForUser(int userId) { + removeAllFingerprintForUser(userId); + removeAllFaceForUser(userId); + } + + private void removeAllFingerprintForUser(final int userId) { + FingerprintManager mFingerprintManager = mInjector.getFingerprintManager(); + if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { + if (mFingerprintManager.hasEnrolledFingerprints(userId)) { + mFingerprintManager.setActiveUser(userId); + CountDownLatch latch = new CountDownLatch(1); + // For the purposes of M and N, groupId is the same as userId. + Fingerprint finger = new Fingerprint(null, userId, 0, 0); + mFingerprintManager.remove(finger, userId, + fingerprintManagerRemovalCallback(latch)); + try { + latch.await(10000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "Latch interrupted when removing fingerprint", e); + } + } + } + } + + private void removeAllFaceForUser(final int userId) { + FaceManager mFaceManager = mInjector.getFaceManager(); + if (mFaceManager != null && mFaceManager.isHardwareDetected()) { + if (mFaceManager.hasEnrolledTemplates(userId)) { + mFaceManager.setActiveUser(userId); + CountDownLatch latch = new CountDownLatch(1); + Face face = new Face(null, 0, 0); + mFaceManager.remove(face, userId, faceManagerRemovalCallback(latch)); + try { + latch.await(10000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "Latch interrupted when removing face", e); + } + } + } + } + + private FingerprintManager.RemovalCallback fingerprintManagerRemovalCallback( + CountDownLatch latch) { + return new FingerprintManager.RemovalCallback() { + @Override + public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence err) { + Slog.e(TAG, String.format( + "Can't remove fingerprint %d in group %d. Reason: %s", + fp.getBiometricId(), fp.getGroupId(), err)); + latch.countDown(); + } + + @Override + public void onRemovalSucceeded(Fingerprint fp, int remaining) { + if (remaining == 0) { + latch.countDown(); + } + } + }; + } + + private FaceManager.RemovalCallback faceManagerRemovalCallback(CountDownLatch latch) { + return new FaceManager.RemovalCallback() { + @Override + public void onRemovalError(Face face, int errMsgId, CharSequence err) { + Slog.e(TAG, String.format("Can't remove face %d. Reason: %s", + face.getBiometricId(), err)); + latch.countDown(); + } + + @Override + public void onRemovalSucceeded(Face face, int remaining) { + if (remaining == 0) { + latch.countDown(); + } + } + }; + } + @GuardedBy("mSpManager") private boolean spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType, byte[] savedCredential, int requestedQuality, int userId, diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 043c834230d1..668f2be158c6 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.media.IMediaRouter2Client; import android.media.IMediaRouter2Manager; +import android.media.IMediaRouterClient; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.os.Binder; @@ -86,7 +87,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - registerClientLocked(client, uid, pid, packageName, userId, trusted); + registerClient2Locked(client, uid, pid, packageName, userId, trusted); } } finally { Binder.restoreCallingIdentity(token); @@ -99,7 +100,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - unregisterClientLocked(client, false); + unregisterClient2Locked(client, false); } } finally { Binder.restoreCallingIdentity(token); @@ -155,14 +156,30 @@ class MediaRouter2ServiceImpl { } } - public void setControlCategories(@NonNull IMediaRouter2Client client, + //TODO: What would happen if a media app used MediaRouter and MediaRouter2 simultaneously? + public void setControlCategories(@NonNull IMediaRouterClient client, + @Nullable List<String> categories) { + Objects.requireNonNull(client, "client must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + setControlCategoriesLocked(clientRecord, categories); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void setControlCategories2(@NonNull IMediaRouter2Client client, @Nullable List<String> categories) { Objects.requireNonNull(client, "client must not be null"); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setControlCategoriesLocked(client, categories); + ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + setControlCategoriesLocked(clientRecord, categories); } } finally { Binder.restoreCallingIdentity(token); @@ -174,7 +191,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - selectRoute2Locked(client, route); + selectRoute2Locked(mAllClientRecords.get(client.asBinder()), route); } } finally { Binder.restoreCallingIdentity(token); @@ -193,6 +210,36 @@ class MediaRouter2ServiceImpl { } } + public void registerClient(@NonNull IMediaRouterClient client, @NonNull String packageName) { + Objects.requireNonNull(client, "client must not be null"); + + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); + final int userId = UserHandle.getUserId(uid); + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + registerClient1Locked(client, packageName, userId); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void unregisterClient(@NonNull IMediaRouterClient client) { + Objects.requireNonNull(client, "client must not be null"); + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + unregisterClient1Locked(client); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + //TODO: Review this is handling multi-user properly. void switchUser() { synchronized (mLock) { @@ -217,9 +264,9 @@ class MediaRouter2ServiceImpl { } } - void clientDied(ClientRecord clientRecord) { + void clientDied(Client2Record clientRecord) { synchronized (mLock) { - unregisterClientLocked(clientRecord.mClient, true); + unregisterClient2Locked(clientRecord.mClient, true); } } @@ -229,18 +276,18 @@ class MediaRouter2ServiceImpl { } } - private void registerClientLocked(IMediaRouter2Client client, + private void registerClient2Locked(IMediaRouter2Client client, int uid, int pid, String packageName, int userId, boolean trusted) { final IBinder binder = client.asBinder(); - ClientRecord clientRecord = mAllClientRecords.get(binder); - if (clientRecord == null) { + if (mAllClientRecords.get(binder) == null) { boolean newUser = false; UserRecord userRecord = mUserRecords.get(userId); if (userRecord == null) { userRecord = new UserRecord(userId); newUser = true; } - clientRecord = new ClientRecord(userRecord, client, uid, pid, packageName, trusted); + Client2Record clientRecord = new Client2Record(userRecord, client, uid, pid, + packageName, trusted); try { binder.linkToDeath(clientRecord, 0); } catch (RemoteException ex) { @@ -261,8 +308,8 @@ class MediaRouter2ServiceImpl { } } - private void unregisterClientLocked(IMediaRouter2Client client, boolean died) { - ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); + private void unregisterClient2Locked(IMediaRouter2Client client, boolean died) { + Client2Record clientRecord = (Client2Record) mAllClientRecords.remove(client.asBinder()); if (clientRecord != null) { UserRecord userRecord = clientRecord.mUserRecord; userRecord.mClientRecords.remove(clientRecord); @@ -272,8 +319,7 @@ class MediaRouter2ServiceImpl { } } - private void selectRoute2Locked(IMediaRouter2Client client, MediaRoute2Info route) { - ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + private void selectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) { if (clientRecord != null) { MediaRoute2Info oldRoute = clientRecord.mSelectedRoute; clientRecord.mSelectedRoute = route; @@ -294,10 +340,7 @@ class MediaRouter2ServiceImpl { } } - private void setControlCategoriesLocked(IMediaRouter2Client client, List<String> categories) { - final IBinder binder = client.asBinder(); - ClientRecord clientRecord = mAllClientRecords.get(binder); - + private void setControlCategoriesLocked(ClientRecord clientRecord, List<String> categories) { if (clientRecord != null) { clientRecord.mControlCategories = categories; @@ -349,9 +392,7 @@ class MediaRouter2ServiceImpl { obtainMessage(UserHandler::notifyProviderInfosUpdatedToManager, userRecord.mHandler, manager)); - final int count = userRecord.mClientRecords.size(); - for (int i = 0; i < count; i++) { - ClientRecord clientRecord = userRecord.mClientRecords.get(i); + for (ClientRecord clientRecord : userRecord.mClientRecords) { clientRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::updateClientUsage, clientRecord.mUserRecord.mHandler, clientRecord)); @@ -378,7 +419,7 @@ class MediaRouter2ServiceImpl { Slog.w(TAG, "Ignoring route selection for unknown client."); } if (clientRecord != null && managerRecord.mTrusted) { - selectRoute2Locked(clientRecord.mClient, route); + selectRoute2Locked(clientRecord, route); } } } @@ -409,6 +450,37 @@ class MediaRouter2ServiceImpl { } } + private void registerClient1Locked(IMediaRouterClient client, String packageName, + int userId) { + final IBinder binder = client.asBinder(); + if (mAllClientRecords.get(binder) == null) { + boolean newUser = false; + UserRecord userRecord = mUserRecords.get(userId); + if (userRecord == null) { + userRecord = new UserRecord(userId); + newUser = true; + } + ClientRecord clientRecord = new Client1Record(userRecord, client, packageName); + + if (newUser) { + mUserRecords.put(userId, userRecord); + initializeUserLocked(userRecord); + } + + userRecord.mClientRecords.add(clientRecord); + mAllClientRecords.put(binder, clientRecord); + } + } + + private void unregisterClient1Locked(IMediaRouterClient client) { + ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); + if (clientRecord != null) { + UserRecord userRecord = clientRecord.mUserRecord; + userRecord.mClientRecords.remove(clientRecord); + disposeUserIfNeededLocked(userRecord); + } + } + final class UserRecord { public final int mUserId; final ArrayList<ClientRecord> mClientRecords = new ArrayList<>(); @@ -430,25 +502,43 @@ class MediaRouter2ServiceImpl { } } - final class ClientRecord implements IBinder.DeathRecipient { + class ClientRecord { public final UserRecord mUserRecord; + public final String mPackageName; + public List<String> mControlCategories; + public MediaRoute2Info mSelectedRoute; + + ClientRecord(UserRecord userRecord, String packageName) { + mUserRecord = userRecord; + mPackageName = packageName; + mControlCategories = Collections.emptyList(); + } + } + + final class Client1Record extends ClientRecord { + public final IMediaRouterClient mClient; + + Client1Record(UserRecord userRecord, IMediaRouterClient client, + String packageName) { + super(userRecord, packageName); + mClient = client; + } + } + + final class Client2Record extends ClientRecord + implements IBinder.DeathRecipient { public final IMediaRouter2Client mClient; public final int mUid; public final int mPid; - public final String mPackageName; public final boolean mTrusted; - public List<String> mControlCategories; - public MediaRoute2Info mSelectedRoute; - ClientRecord(UserRecord userRecord, IMediaRouter2Client client, + Client2Record(UserRecord userRecord, IMediaRouter2Client client, int uid, int pid, String packageName, boolean trusted) { - mUserRecord = userRecord; + super(userRecord, packageName); mClient = client; mUid = uid; mPid = pid; - mPackageName = packageName; mTrusted = trusted; - mControlCategories = Collections.emptyList(); } public void dispose() { @@ -622,7 +712,9 @@ class MediaRouter2ServiceImpl { managers.add(managerRecord.mManager); } for (ClientRecord clientRecord : mUserRecord.mClientRecords) { - clients.add(clientRecord.mClient); + if (clientRecord instanceof Client2Record) { + clients.add(((Client2Record) clientRecord).mClient); + } } } for (IMediaRouter2Manager manager : managers) { diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 2670cd8247ac..796a25d7e295 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -249,6 +249,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted); } + mService2.registerClient(client, packageName); } finally { Binder.restoreCallingIdentity(token); } @@ -289,6 +290,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { unregisterClientLocked(client, false); } + mService2.unregisterClient(client); } finally { Binder.restoreCallingIdentity(token); } @@ -395,6 +397,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void setControlCategories(IMediaRouterClient client, List<String> controlCategories) { + mService2.setControlCategories(client, controlCategories); + } + + // Binder call + @Override public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) { if (client == null) { throw new IllegalArgumentException("client must not be null"); @@ -487,8 +495,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public void setControlCategories(IMediaRouter2Client client, List<String> categories) { - mService2.setControlCategories(client, categories); + public void setControlCategories2(IMediaRouter2Client client, List<String> categories) { + mService2.setControlCategories2(client, categories); } void restoreBluetoothA2dp() { @@ -561,6 +569,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { unregisterClientLocked(clientRecord.mClient, true); } + mService2.unregisterClient(clientRecord.mClient); } private void registerClientLocked(IMediaRouterClient client, diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 8b242242cbe3..a7d423784b4b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -259,6 +259,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK // atomic install which needs to query sessions, which requires lock on mSessions. for (PackageInstallerSession session : stagedSessionsToRestore) { + if (mPm.isDeviceUpgrading()) { + session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Build fingerprint has changed"); + } mStagingManager.restoreSession(session); } // Broadcasts are not sent while we restore sessions on boot, since no processes would be diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f15391a1f1cd..86340d40e3c9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -19980,7 +19980,11 @@ public class PackageManagerService extends IPackageManager.Stub } } synchronized (mLock) { - scheduleWritePackageRestrictionsLocked(userId); + if ((flags & PackageManager.SYNCHRONOUS) != 0) { + flushPackageRestrictionsAsUserInternalLocked(userId); + } else { + scheduleWritePackageRestrictionsLocked(userId); + } updateSequenceNumberLP(pkgSetting, new int[] { userId }); final long callingId = Binder.clearCallingIdentity(); try { @@ -20041,11 +20045,16 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/, false /* checkShell */, "flushPackageRestrictions"); synchronized (mLock) { - mSettings.writePackageRestrictionsLPr(userId); - mDirtyUsers.remove(userId); - if (mDirtyUsers.isEmpty()) { - mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS); - } + flushPackageRestrictionsAsUserInternalLocked(userId); + } + } + + @GuardedBy("mLock") + private void flushPackageRestrictionsAsUserInternalLocked(int userId) { + mSettings.writePackageRestrictionsLPr(userId); + mDirtyUsers.remove(userId); + if (mDirtyUsers.isEmpty()) { + mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 944aefb07f99..1c1c947c0a9e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -751,7 +751,7 @@ class PackageManagerShellCommand extends ShellCommand { (!listThirdParty || !isSystem) && (!listApexOnly || isApex)) { pw.print("package:"); - if (showSourceDir && !isApex) { + if (showSourceDir) { pw.print(info.applicationInfo.sourceDir); pw.print("="); } @@ -2415,6 +2415,7 @@ class PackageManagerShellCommand extends ShellCommand { int userId = -1; int flags = 0; String opt; + boolean preCreateOnly = false; while ((opt = getNextOption()) != null) { if ("--profileOf".equals(opt)) { userId = UserHandle.parseUserArg(getNextArgRequired()); @@ -2428,6 +2429,8 @@ class PackageManagerShellCommand extends ShellCommand { flags |= UserInfo.FLAG_GUEST; } else if ("--demo".equals(opt)) { flags |= UserInfo.FLAG_DEMO; + } else if ("--pre-create-only".equals(opt)) { + preCreateOnly = true; } else { getErrPrintWriter().println("Error: unknown option " + opt); return 1; @@ -2451,7 +2454,7 @@ class PackageManagerShellCommand extends ShellCommand { accm.addSharedAccountsFromParentUser(parentUserId, userId, (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell"); } else if (userId < 0) { - info = um.createUser(name, flags); + info = preCreateOnly ? um.preCreateUser(flags) : um.createUser(name, flags); } else { info = um.createProfileForUser(name, flags, userId, null); } @@ -3364,8 +3367,11 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]"); pw.println(" Trim cache files to reach the given free space."); pw.println(""); + pw.println(" list users"); + pw.println(" Lists the current users."); + pw.println(""); pw.println(" create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral]"); - pw.println(" [--guest] USER_NAME"); + pw.println(" [--guest] [--pre-create-only] USER_NAME"); pw.println(" Create a new user with the given USER_NAME, printing the new user identifier"); pw.println(" of the user."); pw.println(""); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index dace598a790b..8431fa36c04c 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -41,6 +41,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; +import android.content.pm.UserInfo.UserInfoFlag; import android.content.res.Resources; import android.graphics.Bitmap; import android.os.Binder; @@ -158,6 +159,7 @@ public class UserManagerService extends IUserManager.Stub { private static final String ATTR_SERIAL_NO = "serialNumber"; private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; private static final String ATTR_PARTIAL = "partial"; + private static final String ATTR_PRE_CREATED = "preCreated"; private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove"; private static final String ATTR_USER_VERSION = "version"; private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId"; @@ -597,7 +599,8 @@ public class UserManagerService extends IUserManager.Stub { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { UserInfo ui = mUsers.valueAt(i).info; - if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) { + if ((ui.partial || ui.guestToRemove || (ui.isEphemeral() && !ui.preCreated)) + && i != 0) { partials.add(ui); addRemovingUserIdLocked(ui.id); ui.partial = true; @@ -660,20 +663,25 @@ public class UserManagerService extends IUserManager.Stub { return null; } - @Override public @NonNull List<UserInfo> getUsers(boolean excludeDying) { + return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */ true); + } + + @Override + public @NonNull List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, + boolean excludePreCreated) { checkManageOrCreateUsersPermission("query users"); synchronized (mUsersLock) { ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { UserInfo ui = mUsers.valueAt(i).info; - if (ui.partial) { + if ((excludePartial && ui.partial) + || (excludeDying && mRemovingUserIds.get(ui.id)) + || (excludePreCreated && ui.preCreated)) { continue; } - if (!excludeDying || !mRemovingUserIds.get(ui.id)) { - users.add(userWithName(ui)); - } + users.add(userWithName(ui)); } return users; } @@ -1196,7 +1204,7 @@ public class UserManagerService extends IUserManager.Stub { private void checkManageOrInteractPermIfCallerInOtherProfileGroup(@UserIdInt int userId, String name) { - int callingUserId = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) || hasManageUsersPermission()) { return; @@ -1210,7 +1218,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean isDemoUser(@UserIdInt int userId) { - int callingUserId = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); if (callingUserId != userId && !hasManageUsersPermission()) { throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId + " is a demo user"); @@ -1222,6 +1230,19 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean isPreCreated(@UserIdInt int userId) { + final int callingUserId = UserHandle.getCallingUserId(); + if (callingUserId != userId && !hasManageUsersPermission()) { + throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId + + " is pre-created"); + } + synchronized (mUsersLock) { + UserInfo userInfo = getUserInfoLU(userId); + return userInfo != null && userInfo.preCreated; + } + } + + @Override public boolean isRestricted() { synchronized (mUsersLock) { return getUserInfoLU(UserHandle.getCallingUserId()).isRestricted(); @@ -1871,7 +1892,7 @@ public class UserManagerService extends IUserManager.Stub { // Skip over users being removed for (int i = 0; i < totalUserCount; i++) { UserInfo user = mUsers.valueAt(i).info; - if (!mRemovingUserIds.get(user.id) && !user.isGuest()) { + if (!mRemovingUserIds.get(user.id) && !user.isGuest() && !user.preCreated) { aliveUserCount++; } } @@ -2362,6 +2383,9 @@ public class UserManagerService extends IUserManager.Stub { if (userInfo.partial) { serializer.attribute(null, ATTR_PARTIAL, "true"); } + if (userInfo.preCreated) { + serializer.attribute(null, ATTR_PRE_CREATED, "true"); + } if (userInfo.guestToRemove) { serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true"); } @@ -2518,6 +2542,7 @@ public class UserManagerService extends IUserManager.Stub { int profileBadge = 0; int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID; boolean partial = false; + boolean preCreated = false; boolean guestToRemove = false; boolean persistSeedData = false; String seedAccountName = null; @@ -2562,6 +2587,10 @@ public class UserManagerService extends IUserManager.Stub { if ("true".equals(valueString)) { partial = true; } + valueString = parser.getAttributeValue(null, ATTR_PRE_CREATED); + if ("true".equals(valueString)) { + preCreated = true; + } valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE); if ("true".equals(valueString)) { guestToRemove = true; @@ -2615,6 +2644,7 @@ public class UserManagerService extends IUserManager.Stub { userInfo.lastLoggedInTime = lastLoggedInTime; userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint; userInfo.partial = partial; + userInfo.preCreated = preCreated; userInfo.guestToRemove = guestToRemove; userInfo.profileGroupId = profileGroupId; userInfo.profileBadge = profileBadge; @@ -2686,7 +2716,8 @@ public class UserManagerService extends IUserManager.Stub { public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags, @UserIdInt int userId, String[] disallowedPackages) { checkManageOrCreateUsersPermission(flags); - return createUserInternalUnchecked(name, flags, userId, disallowedPackages); + return createUserInternalUnchecked(name, flags, userId, /* preCreate= */ false, + disallowedPackages); } @Override @@ -2701,12 +2732,27 @@ public class UserManagerService extends IUserManager.Stub { return createUserInternal(name, flags, UserHandle.USER_NULL); } - private UserInfo createUserInternal(String name, int flags, int parentId) { + @Override + public UserInfo preCreateUser(int flags) { + checkManageOrCreateUsersPermission(flags); + + Preconditions.checkArgument(!UserInfo.isManagedProfile(flags), + "cannot pre-create managed profiles"); + + Slog.i(LOG_TAG, "Pre-creating user with flags " + UserInfo.flagsToString(flags)); + + return createUserInternalUnchecked(/* name= */ null, flags, + /* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true, + /* disallowedPackages= */ null); + } + + private UserInfo createUserInternal(@Nullable String name, @UserInfoFlag int flags, + @UserIdInt int parentId) { return createUserInternal(name, flags, parentId, null); } - private UserInfo createUserInternal(String name, int flags, int parentId, - String[] disallowedPackages) { + private UserInfo createUserInternal(@Nullable String name, @UserInfoFlag int flags, + @UserIdInt int parentId, @Nullable String[] disallowedPackages) { String restriction = ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0) ? UserManager.DISALLOW_ADD_MANAGED_PROFILE : UserManager.DISALLOW_ADD_USER; @@ -2714,21 +2760,56 @@ public class UserManagerService extends IUserManager.Stub { Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled."); return null; } - return createUserInternalUnchecked(name, flags, parentId, disallowedPackages); + return createUserInternalUnchecked(name, flags, parentId, /* preCreate= */ false, + disallowedPackages); } - private UserInfo createUserInternalUnchecked(@Nullable String name, int flags, - int parentId, @Nullable String[] disallowedPackages) { - TimingsTraceAndSlog t = new TimingsTraceAndSlog(); - t.traceBegin("createUser"); - UserInfo userInfo = - createUserInternalUncheckedNoTracing(name, flags, parentId, disallowedPackages, t); - t.traceEnd(); - return userInfo; + private UserInfo createUserInternalUnchecked(@Nullable String name, @UserInfoFlag int flags, + @UserIdInt int parentId, boolean preCreate, + @Nullable String[] disallowedPackages) { + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); + t.traceBegin("createUser-" + flags); + try { + return createUserInternalUncheckedNoTracing(name, flags, parentId, preCreate, + disallowedPackages, t); + } finally { + t.traceEnd(); + } } - private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name, int flags, - int parentId, @Nullable String[] disallowedPackages, @NonNull TimingsTraceAndSlog t) { + private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name, + @UserInfoFlag int flags, @UserIdInt int parentId, boolean preCreate, + @Nullable String[] disallowedPackages, @NonNull TimingsTraceAndSlog t) { + + // First try to use a pre-created user (if available). + // NOTE: currently we don't support pre-created managed profiles + if (!preCreate && (parentId < 0 && !UserInfo.isManagedProfile(flags))) { + final UserData preCreatedUserData; + synchronized (mUsersLock) { + preCreatedUserData = getPreCreatedUserLU(flags); + } + if (preCreatedUserData != null) { + final UserInfo preCreatedUser = preCreatedUserData.info; + Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " for flags + " + + UserInfo.flagsToString(flags)); + if (DBG) { + Log.d(LOG_TAG, "pre-created user flags: " + + UserInfo.flagsToString(preCreatedUser.flags) + + " new-user flags: " + UserInfo.flagsToString(flags)); + } + preCreatedUser.name = name; + preCreatedUser.preCreated = false; + preCreatedUser.creationTime = getCreationTime(); + + dispatchUserAddedIntent(preCreatedUser); + + writeUserLP(preCreatedUserData); + writeUserListLP(); + + return preCreatedUser; + } + } + DeviceStorageMonitorInternal dsm = LocalServices .getService(DeviceStorageMonitorInternal.class); if (dsm.isMemoryLow()) { @@ -2736,8 +2817,8 @@ public class UserManagerService extends IUserManager.Stub { return null; } - final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0; - final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0; + final boolean isGuest = UserInfo.isGuest(flags); + final boolean isManagedProfile = UserInfo.isManagedProfile(flags); final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0; final boolean isDemo = (flags & UserInfo.FLAG_DEMO) != 0; final long ident = Binder.clearCallingIdentity(); @@ -2758,8 +2839,8 @@ public class UserManagerService extends IUserManager.Stub { return null; } if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) { - // If we're not adding a guest/demo user or a managed profile and the limit has - // been reached, cannot add a user. + // If we're not adding a guest/demo user or a managed profile, + // and the limit has been reached, cannot add a user. Log.e(LOG_TAG, "Cannot add user. Maximum user limit is reached."); return null; } @@ -2794,8 +2875,7 @@ public class UserManagerService extends IUserManager.Stub { userId = getNextAvailableId(); Environment.getUserSystemDirectory(userId).mkdirs(); - boolean ephemeralGuests = Resources.getSystem() - .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral); + boolean ephemeralGuests = areGuestUsersEphemeral(); synchronized (mUsersLock) { // Add ephemeral flag to guests/users if required. Also inherit it from parent. @@ -2806,9 +2886,9 @@ public class UserManagerService extends IUserManager.Stub { userInfo = new UserInfo(userId, name, null, flags); userInfo.serialNumber = mNextSerialNumber++; - long now = System.currentTimeMillis(); - userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0; + userInfo.creationTime = getCreationTime(); userInfo.partial = true; + userInfo.preCreated = preCreate; userInfo.lastLoggedInFingerprint = Build.FINGERPRINT; if (isManagedProfile && parentId != UserHandle.USER_NULL) { userInfo.profileBadge = getFreeProfileBadgeLU(parentId); @@ -2869,17 +2949,40 @@ public class UserManagerService extends IUserManager.Stub { t.traceBegin("PM.onNewUserCreated"); mPm.onNewUserCreated(userId); - t.traceEnd(); - Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); - addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL, - android.Manifest.permission.MANAGE_USERS); - MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED - : (isDemo ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1); + if (preCreate) { + // Must start user (which will be stopped right away, through + // UserController.finishUserUnlockedCompleted) so services can properly + // intialize it. + // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback + // on SystemService instead. + Slog.i(LOG_TAG, "starting pre-created user " + userInfo.toFullString()); + final IActivityManager am = ActivityManager.getService(); + try { + am.startUserInBackground(userId); + } catch (RemoteException e) { + Slog.w(LOG_TAG, "could not start pre-created user " + userId, e); + } + } else { + dispatchUserAddedIntent(userInfo); + } + } finally { Binder.restoreCallingIdentity(ident); } + + // TODO(b/140750212): it's possible to reach "max users overflow" when the user is created + // "from scratch" (i.e., not from a pre-created user) and reaches the maximum number of + // users without counting the pre-created one. Then when the pre-created is converted, the + // "effective" number of max users is exceeds. Example: + // Max: 3 Current: 2 full (u0 and u10) + 1 pre-created (u11) + // Step 1: create(/* flags doesn't match u11 */): u12 is created, "effective max" is now 3 + // (u0, u10, u12) but "real" max is 4 (u0, u10, u11, u12) + // Step 2: create(/* flags match u11 */): u11 is converted, now "effective max" is also 4 + // (u0, u10, u11, u12) + // One way to avoid this issue is by removing a pre-created user from the pool when the + // "real" max exceeds the max here. + return userInfo; } @@ -2888,6 +2991,62 @@ public class UserManagerService extends IUserManager.Stub { return mSystemPackageInstaller.installWhitelistedSystemPackages(isFirstBoot, isUpgrade); } + private long getCreationTime() { + final long now = System.currentTimeMillis(); + return (now > EPOCH_PLUS_30_YEARS) ? now : 0; + } + + private void dispatchUserAddedIntent(@NonNull UserInfo userInfo) { + Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); + mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL, + android.Manifest.permission.MANAGE_USERS); + MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED + : (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1); + } + + private boolean areGuestUsersEphemeral() { + return Resources.getSystem() + .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral); + } + + /** + * Gets a pre-created user for the given flag. + * + * <p>Should be used only during user creation, so the pre-created user can be used (instead of + * creating and initializing a new user from scratch). + */ + // TODO(b/140750212): add unit test + @GuardedBy("mUsersLock") + private @Nullable UserData getPreCreatedUserLU(@UserInfoFlag int flags) { + if (DBG) { + Slog.d(LOG_TAG, "getPreCreatedUser(): initialFlags= " + UserInfo.flagsToString(flags)); + } + flags |= UserInfo.FLAG_FULL; + if (UserInfo.isGuest(flags) && areGuestUsersEphemeral()) { + flags |= UserInfo.FLAG_EPHEMERAL; + } + if (DBG) { + Slog.d(LOG_TAG, "getPreCreatedUser(): targetFlags= " + UserInfo.flagsToString(flags)); + } + final int userSize = mUsers.size(); + for (int i = 0; i < userSize; i++) { + final UserData user = mUsers.valueAt(i); + if (DBG) Slog.d(LOG_TAG, i + ":" + user.info.toFullString()); + if (user.info.preCreated + && (user.info.flags & ~UserInfo.FLAG_INITIALIZED) == flags) { + if (!user.info.isInitialized()) { + Slog.w(LOG_TAG, "found pre-created user for flags " + + "" + UserInfo.flagsToString(flags) + + ", but it's not initialized yet: " + user.info.toFullString()); + continue; + } + return user; + } + } + return null; + } + @VisibleForTesting UserData putUserInfo(UserInfo userInfo) { final UserData userData = new UserData(); @@ -3728,7 +3887,7 @@ public class UserManagerService extends IUserManager.Stub { try { switch(cmd) { case "list": - return runList(pw); + return runList(pw, shell); default: return shell.handleDefaultCommands(cmd); } @@ -3738,17 +3897,58 @@ public class UserManagerService extends IUserManager.Stub { return -1; } - private int runList(PrintWriter pw) throws RemoteException { + private int runList(PrintWriter pw, Shell shell) throws RemoteException { + boolean all = false; + boolean verbose = false; + String opt; + while ((opt = shell.getNextOption()) != null) { + switch (opt) { + case "-v": + verbose = true; + break; + case "--all": + all = true; + break; + default: + pw.println("Invalid option: " + opt); + return -1; + } + } final IActivityManager am = ActivityManager.getService(); - final List<UserInfo> users = getUsers(false); + final List<UserInfo> users = getUsers(/* excludePartial= */ !all, + /* excludingDying=*/ false, /* excludePreCreated= */ !all); if (users == null) { pw.println("Error: couldn't get users"); return 1; } else { - pw.println("Users:"); - for (int i = 0; i < users.size(); i++) { - String running = am.isUserRunning(users.get(i).id, 0) ? " running" : ""; - pw.println("\t" + users.get(i).toString() + running); + final int size = users.size(); + int currentUser = UserHandle.USER_NULL; + if (verbose) { + pw.printf("%d users:\n\n", size); + currentUser = am.getCurrentUser().id; + } else { + // NOTE: the standard "list users" command is used by integration tests and + // hence should not be changed. If you need to add more info, use the + // verbose option. + pw.println("Users:"); + } + for (int i = 0; i < size; i++) { + final UserInfo user = users.get(i); + final boolean running = am.isUserRunning(user.id, 0); + final boolean current = user.id == currentUser; + if (verbose) { + pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s\n", i, user.id, user.name, + UserInfo.flagsToString(user.flags), + running ? " (running)" : "", + user.partial ? " (partial)" : "", + user.preCreated ? " (pre-created)" : "", + current ? " (current)" : ""); + } else { + // NOTE: the standard "list users" command is used by integration tests and + // hence should not be changed. If you need to add more info, use the + // verbose option. + pw.printf("\t%s%s\n", user, running ? " running" : ""); + } } return 0; } @@ -3785,6 +3985,9 @@ public class UserManagerService extends IUserManager.Stub { if (userInfo.partial) { pw.print(" <partial>"); } + if (userInfo.preCreated) { + pw.print(" <pre-created>"); + } pw.println(); pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" ("); pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")"); @@ -3867,10 +4070,10 @@ public class UserManagerService extends IUserManager.Stub { // Dump some capabilities pw.println(); - pw.println(" Max users: " + UserManager.getMaxSupportedUsers()); + pw.print(" Max users: " + UserManager.getMaxSupportedUsers()); + pw.println(" (limit reached: " + isUserLimitReached() + ")"); pw.println(" Supports switchable users: " + UserManager.supportsMultipleUsers()); - pw.println(" All guests ephemeral: " + Resources.getSystem().getBoolean( - com.android.internal.R.bool.config_guestUserEphemeral)); + pw.println(" All guests ephemeral: " + areGuestUsersEphemeral()); pw.println(" Is split-system user: " + UserManager.isSplitSystemUser()); pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode()); pw.println(" User version: " + mUserVersion); @@ -4076,7 +4279,7 @@ public class UserManagerService extends IUserManager.Stub { public UserInfo createUserEvenWhenDisallowed(String name, int flags, String[] disallowedPackages) { UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL, - disallowedPackages); + /* preCreated= */ false, disallowedPackages); // Keep this in sync with UserManager.createUser if (user != null && !user.isAdmin() && !user.isDemo()) { setUserRestriction(UserManager.DISALLOW_SMS, true, user.id); @@ -4270,7 +4473,7 @@ public class UserManagerService extends IUserManager.Stub { pw.println(" help"); pw.println(" Print this help text."); pw.println(""); - pw.println(" list"); + pw.println(" list [-v] [-all]"); pw.println(" Prints all users on the system."); } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 53156345bb4e..4213168b6ec7 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1558,7 +1558,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { } }; - final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); for (int i = 0; i < permissionCount; i++) { final String permName = pkg.requestedPermissions.get(i); final BasePermission bp; @@ -1624,16 +1623,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If this permission was granted by default, make sure it is. if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) { + // PermissionPolicyService will handle the app op for runtime permissions later. grantRuntimePermissionInternal(permName, packageName, false, Process.SYSTEM_UID, userId, delayingPermCallback); - // Allow app op later as we are holding mPackages - // PermissionPolicyService will handle the app op for foreground/background - // permissions. - String appOp = AppOpsManager.permissionToOp(permName); - if (appOp != null) { - mHandler.post(() -> appOpsManager.setUidMode(appOp, uid, - AppOpsManager.MODE_ALLOWED)); - } // If permission review is enabled the permissions for a legacy apps // are represented as constantly granted runtime ones, so don't revoke. } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index f3826e9ee4c9..77c16e37b51d 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -424,16 +424,6 @@ public final class PermissionPolicyService extends SystemService { */ private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>(); - /** - * All ops that need to be flipped to foreground if allow. - * - * Currently, only used by the foreground/background permissions logic. - * - * @see #syncPackages - */ - private final @NonNull ArrayList<OpToChange> mOpsToForegroundIfAllow = - new ArrayList<>(); - PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; mPackageManager = context.getPackageManager(); @@ -443,7 +433,7 @@ public final class PermissionPolicyService extends SystemService { /** * Set app ops that were added in {@link #addPackage}. * - * <p>This processes ops previously added by {@link #addOpIfRestricted} + * <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)} */ private void syncPackages() { // Remember which ops were already set. This makes sure that we always set the most @@ -459,19 +449,6 @@ public final class PermissionPolicyService extends SystemService { alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } - final int foregroundIfAllowedCount = mOpsToForegroundIfAllow.size(); - for (int i = 0; i < foregroundIfAllowedCount; i++) { - final OpToChange op = mOpsToForegroundIfAllow.get(i); - if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { - continue; - } - - boolean wasSet = setUidModeForegroundIfAllow(op.code, op.uid, op.packageName); - if (wasSet) { - alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); - } - } - final int foregroundCount = mOpsToForeground.size(); for (int i = 0; i < foregroundCount; i++) { final OpToChange op = mOpsToForeground.get(i); @@ -509,143 +486,139 @@ public final class PermissionPolicyService extends SystemService { } /** - * Add op that belong to a restricted permission for later processing in - * {@link #syncPackages()}. - * - * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. - * - * @param permissionInfo The permission that is currently looked at - * @param pkg The package looked at + * Note: Called with the package lock held. Do <u>not</u> call into app-op manager. */ - private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo, - @NonNull PackageInfo pkg) { - final String permission = permissionInfo.name; - final int opCode = getSwitchOp(permission); - final int uid = pkg.applicationInfo.uid; + private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull String permissionName) { + PermissionInfo permissionInfo = getPermissionInfo(permissionName); + if (permissionInfo == null) { + return; + } + addPermissionAppOp(packageInfo, permissionInfo); + addExtraAppOp(packageInfo, permissionInfo); + } - if (!permissionInfo.isRestricted()) { + private void addPermissionAppOp(@NonNull PackageInfo packageInfo, + @NonNull PermissionInfo permissionInfo) { + if (!permissionInfo.isRuntime()) { return; } - if (opCode != OP_NONE) { - int permissionFlags = mPackageManager.getPermissionFlags(permission, - pkg.packageName, mContext.getUser()); - boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; - if (!isReviewRequired) { - boolean isRevokedCompat = - (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT) != 0; - if (permissionInfo.isHardRestricted()) { - boolean shouldApplyRestriction = - (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; - if (isRevokedCompat || shouldApplyRestriction) { - mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, opCode)); - } else { - mOpsToAllow.add(new OpToChange(uid, pkg.packageName, opCode)); - } - } else if (permissionInfo.isSoftRestricted()) { - SoftRestrictedPermissionPolicy policy = - SoftRestrictedPermissionPolicy.forPermission(mContext, - pkg.applicationInfo, mContext.getUser(), permission); - if (!isRevokedCompat && policy.mayGrantPermission()) { - mOpsToAllow.add(new OpToChange(uid, pkg.packageName, opCode)); - } else { - mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, opCode)); - } - } - } + String permissionName = permissionInfo.name; + String packageName = packageInfo.packageName; + int permissionFlags = mPackageManager.getPermissionFlags(permissionName, + packageName, mContext.getUser()); + boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; + if (isReviewRequired) { + return; } - if (permissionInfo.isSoftRestricted()) { - SoftRestrictedPermissionPolicy policy = - SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, - mContext.getUser(), permission); - int extraOpCode = policy.getExtraAppOpCode(); - if (extraOpCode != OP_NONE) { - if (policy.mayAllowExtraAppOp()) { - mOpsToAllow.add(new OpToChange(uid, pkg.packageName, extraOpCode)); - } else { - if (policy.mayDenyExtraAppOpIfGranted()) { - mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, extraOpCode)); - } else { - mOpsToIgnoreIfNotAllowed.add(new OpToChange(uid, pkg.packageName, - extraOpCode)); - } - } + // TODO: COARSE_LOCATION and FINE_LOCATION shares the same app op. We are solving this + // with switch op but once we start syncing single permission this won't work. + int appOpCode = getSwitchOp(permissionName); + if (appOpCode == OP_NONE) { + // Note that background permissions don't have an associated app op. + return; + } + + int appOpMode; + boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, permissionInfo); + if (shouldGrantAppOp) { + if (permissionInfo.backgroundPermission != null) { + PermissionInfo backgroundPermissionInfo = getPermissionInfo( + permissionInfo.backgroundPermission); + boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null + && shouldGrantAppOp(packageInfo, backgroundPermissionInfo); + appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND; + } else { + appOpMode = MODE_ALLOWED; } + } else { + appOpMode = MODE_IGNORED; + } + + int uid = packageInfo.applicationInfo.uid; + OpToChange opToChange = new OpToChange(uid, packageName, appOpCode); + switch (appOpMode) { + case MODE_ALLOWED: + mOpsToAllow.add(opToChange); + break; + case MODE_FOREGROUND: + mOpsToForeground.add(opToChange); + break; + case MODE_IGNORED: + mOpsToIgnore.add(opToChange); + break; } } - private boolean isBgPermRestricted(@NonNull String pkg, @NonNull String perm, int uid) { + @Nullable + private PermissionInfo getPermissionInfo(@NonNull String permissionName) { try { - final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(perm, 0); + return mPackageManager.getPermissionInfo(permissionName, 0); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } - if (bgPermInfo.isSoftRestricted()) { - Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not " - + "implemented"); - } + private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo, + @NonNull PermissionInfo permissionInfo) { + String permissionName = permissionInfo.name; + String packageName = packageInfo.packageName; + boolean isGranted = mPackageManager.checkPermission(permissionName, packageName) + == PackageManager.PERMISSION_GRANTED; + if (!isGranted) { + return false; + } - return bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags( - perm, pkg, UserHandle.getUserHandleForUid(uid)) - & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; - } catch (NameNotFoundException e) { - Slog.w(LOG_TAG, "Cannot read permission state of " + perm, e); + int permissionFlags = mPackageManager.getPermissionFlags(permissionName, packageName, + mContext.getUser()); + boolean isRevokedCompat = (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT) + == FLAG_PERMISSION_REVOKED_COMPAT; + if (isRevokedCompat) { return false; } - } - /** - * Add op that belong to a foreground permission for later processing in - * {@link #syncPackages()}. - * - * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. - * - * @param permissionInfo The permission that is currently looked at - * @param pkg The package looked at - */ - private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo, - @NonNull PackageInfo pkg) { - final String bgPermissionName = permissionInfo.backgroundPermission; + if (permissionInfo.isHardRestricted()) { + boolean shouldApplyRestriction = + (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION) + == FLAG_PERMISSION_APPLY_RESTRICTION; + return !shouldApplyRestriction; + } else if (permissionInfo.isSoftRestricted()) { + SoftRestrictedPermissionPolicy policy = + SoftRestrictedPermissionPolicy.forPermission(mContext, + packageInfo.applicationInfo, mContext.getUser(), permissionName); + return policy.mayGrantPermission(); + } else { + return true; + } + } - if (bgPermissionName == null) { + private void addExtraAppOp(@NonNull PackageInfo packageInfo, + @NonNull PermissionInfo permissionInfo) { + if (!permissionInfo.isSoftRestricted()) { return; } - final String permission = permissionInfo.name; - final int opCode = getSwitchOp(permission); - final String pkgName = pkg.packageName; - final int uid = pkg.applicationInfo.uid; - - // App does not support runtime permissions. Hence the state is encoded in the app-op. - // To not override unrecoverable state don't change app-op unless bg perm is reviewed. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - // If the review is required for this permission, the grant state does not - // really matter. To have a stable state, don't change the app-op if review is still - // pending. - int flags = mPackageManager.getPermissionFlags(bgPermissionName, - pkg.packageName, UserHandle.getUserHandleForUid(uid)); - - if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0 - && isBgPermRestricted(pkgName, bgPermissionName, uid)) { - mOpsToForegroundIfAllow.add(new OpToChange(uid, pkgName, opCode)); - } - + String permissionName = permissionInfo.name; + SoftRestrictedPermissionPolicy policy = + SoftRestrictedPermissionPolicy.forPermission(mContext, + packageInfo.applicationInfo, mContext.getUser(), permissionName); + int extraOpCode = policy.getExtraAppOpCode(); + if (extraOpCode == OP_NONE) { return; } - if (mPackageManager.checkPermission(permission, pkgName) - == PackageManager.PERMISSION_GRANTED) { - final boolean isBgHardRestricted = isBgPermRestricted(pkgName, bgPermissionName, - uid); - final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName, - pkgName) == PackageManager.PERMISSION_GRANTED; - - if (!isBgHardRestricted && isBgPermGranted) { - mOpsToAllow.add(new OpToChange(uid, pkgName, opCode)); + int uid = packageInfo.applicationInfo.uid; + String packageName = packageInfo.packageName; + OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode); + if (policy.mayAllowExtraAppOp()) { + mOpsToAllow.add(extraOpToChange); + } else { + if (policy.mayDenyExtraAppOpIfGranted()) { + mOpsToIgnore.add(extraOpToChange); } else { - mOpsToForeground.add(new OpToChange(uid, pkgName, opCode)); + mOpsToIgnoreIfNotAllowed.add(extraOpToChange); } - } else { - mOpsToIgnore.add(new OpToChange(uid, pkgName, opCode)); } } @@ -671,20 +644,7 @@ public final class PermissionPolicyService extends SystemService { } for (String permission : pkg.requestedPermissions) { - final int opCode = getSwitchOp(permission); - if (opCode == OP_NONE) { - continue; - } - - final PermissionInfo permissionInfo; - try { - permissionInfo = mPackageManager.getPermissionInfo(permission, 0); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - - addOpIfRestricted(permissionInfo, pkg); - addOpIfFgPermissions(permissionInfo, pkg); + addAppOps(pkg, permission); } } @@ -692,17 +652,6 @@ public final class PermissionPolicyService extends SystemService { setUidMode(opCode, uid, MODE_ALLOWED, packageName); } - private boolean setUidModeForegroundIfAllow(int opCode, int uid, - @NonNull String packageName) { - final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( - opCode), uid, packageName); - if (currentMode == MODE_ALLOWED) { - mAppOpsManager.setUidMode(opCode, uid, MODE_FOREGROUND); - return true; - } - return false; - } - private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) { setUidMode(opCode, uid, MODE_FOREGROUND, packageName); } diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java index 712012d9e621..017c684e7449 100644 --- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java +++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java @@ -21,6 +21,7 @@ import android.annotation.UserIdInt; import android.app.role.RoleManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; @@ -34,9 +35,9 @@ import com.android.internal.util.CollectionUtils; import com.android.server.LocalServices; import com.android.server.role.RoleManagerService; -import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Logic to retrieve the various legacy(pre-Q) equivalents of role holders. @@ -125,9 +126,21 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder } case RoleManager.ROLE_HOME: { PackageManager packageManager = mContext.getPackageManager(); - List<ResolveInfo> resolveInfos = new ArrayList<>(); - ComponentName componentName = packageManager.getHomeActivities(resolveInfos); - String packageName = componentName != null ? componentName.getPackageName() : null; + String packageName; + if (packageManager.isDeviceUpgrading()) { + ResolveInfo resolveInfo = packageManager.resolveActivityAsUser( + new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), + PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + packageName = resolveInfo != null && resolveInfo.activityInfo != null + ? resolveInfo.activityInfo.packageName : null; + if (packageName != null && isSettingsApplication(packageName, userId)) { + packageName = null; + } + } else { + packageName = null; + } return CollectionUtils.singletonOrEmpty(packageName); } case RoleManager.ROLE_EMERGENCY: { @@ -142,4 +155,16 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder } } } + + private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) { + PackageManager packageManager = mContext.getPackageManager(); + ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent( + Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + if (resolveInfo == null || resolveInfo.activityInfo == null) { + return false; + } + return Objects.equals(packageName, resolveInfo.activityInfo.packageName); + } } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index bf8c042835dd..aac0f906feaa 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -51,7 +51,6 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; -import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -269,6 +268,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C maybeMigrateRole(RoleManager.ROLE_DIALER, userId); maybeMigrateRole(RoleManager.ROLE_SMS, userId); maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId); + maybeMigrateRole(RoleManager.ROLE_HOME, userId); // Some package state has changed, so grant default roles again. Slog.i(LOG_TAG, "Granting default roles..."); @@ -701,40 +701,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C dumpOutputStream.flush(); } - /** - * Get filtered SMS messages for financial app. - */ - @Override - public void getSmsMessagesForFinancialApp( - String callingPkg, Bundle params, IFinancialSmsCallback callback) { - int mode = PermissionChecker.checkCallingOrSelfPermission( - getContext(), - AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); - - if (mode == PermissionChecker.PERMISSION_GRANTED) { - FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext()); - financialSmsManager.getSmsMessages(new RemoteCallback((result) -> { - CursorWindow messages = null; - if (result == null) { - Slog.w(LOG_TAG, "result is null."); - } else { - messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS); - } - try { - callback.onGetSmsMessagesForFinancialApp(messages); - } catch (RemoteException e) { - // do nothing - } - }), params); - } else { - try { - callback.onGetSmsMessagesForFinancialApp(null); - } catch (RemoteException e) { - // do nothing - } - } - } - private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index eadd09cf46ee..425da374a5a8 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -28,6 +28,7 @@ import android.util.Slog; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; @@ -288,19 +289,25 @@ class RollbackStore { JSONObject dataJson = new JSONObject( IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath())); - return new Rollback( - rollbackInfoFromJson(dataJson.getJSONObject("info")), - backupDir, - Instant.parse(dataJson.getString("timestamp")), - dataJson.getInt("stagedSessionId"), - rollbackStateFromString(dataJson.getString("state")), - dataJson.getInt("apkSessionId"), - dataJson.getBoolean("restoreUserDataInProgress")); + return rollbackFromJson(dataJson, backupDir); } catch (JSONException | DateTimeParseException | ParseException e) { throw new IOException(e); } } + @VisibleForTesting + static Rollback rollbackFromJson(JSONObject dataJson, File backupDir) + throws JSONException, ParseException { + return new Rollback( + rollbackInfoFromJson(dataJson.getJSONObject("info")), + backupDir, + Instant.parse(dataJson.getString("timestamp")), + dataJson.getInt("stagedSessionId"), + rollbackStateFromString(dataJson.getString("state")), + dataJson.getInt("apkSessionId"), + dataJson.getBoolean("restoreUserDataInProgress")); + } + private static JSONObject toJson(VersionedPackage pkg) throws JSONException { JSONObject json = new JSONObject(); json.put("packageName", pkg.getPackageName()); diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 4c935643da55..5493afd1b123 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -365,10 +365,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, fout)) return; IndentingPrintWriter pw = new IndentingPrintWriter(fout, " "); - TextClassificationManager tcm = mContext.getSystemService(TextClassificationManager.class); - tcm.dump(pw); - pw.printPair("context", mContext); pw.println(); + // Create a TCM instance with the system server identity. TCM creates a ContentObserver + // to listen for settings changes. It does not pass the checkContentProviderAccess check + // if we are using the shell identity, because AMS does not track of processes spawn from + // shell. + Binder.withCleanCallingIdentity( + () -> mContext.getSystemService(TextClassificationManager.class).dump(pw)); + + pw.printPair("context", mContext); + pw.println(); synchronized (mLock) { int size = mUserStates.size(); pw.print("Number user states: "); pw.println(size); diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 2bdcea5ba94e..9d9a37c13bdd 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -50,9 +50,9 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.RootActivityContainer.FindTaskResult; import static com.android.server.wm.RootActivityContainer.TAG_STATES; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; @@ -76,6 +76,7 @@ import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.am.EventLogTags; +import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -1296,8 +1297,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { final AppWindowToken newFocus; final IBinder token = r.appToken; if (token == null) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId=" - + mDisplayId); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d", + mDisplayId); newFocus = null; } else { newFocus = mService.mWindowManager.mRoot.getAppWindowToken(token); @@ -1305,8 +1306,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token + ", displayId=" + mDisplayId); } - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus - + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, + "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus, + moveFocusNow, mDisplayId); } final boolean changed = mDisplayContent.setFocusedApp(newFocus); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c54ccd4d6844..c9e84ec2c69b 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -154,12 +154,11 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_W import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.TaskPersister.DEBUG; import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; @@ -239,6 +238,7 @@ import com.android.server.AttributeCache.Entry; import com.android.server.am.AppTimeTracker; import com.android.server.am.EventLogTags; import com.android.server.am.PendingIntentRecord; +import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot; import com.android.server.wm.ActivityStack.ActivityState; @@ -1183,11 +1183,10 @@ final class ActivityRecord extends ConfigurationContainer { info.applicationInfo.targetSdkVersion, info.screenOrientation, mRotationAnimationHint, mLaunchTaskBehind, isAlwaysFocusable()); - if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) { - Slog.v(TAG, "addAppToken: " - + mAppWindowToken + " task=" + container + " at " - + Integer.MAX_VALUE); - } + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addAppToken: %s" + + " task=%s at %d", mAppWindowToken, container, + Integer.MAX_VALUE); + container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */); } @@ -1204,12 +1203,11 @@ final class ActivityRecord extends ConfigurationContainer { CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "setAppStartingWindow: token=" + appToken - + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask - + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning - + " allowTaskSnapshot=" + allowTaskSnapshot); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "setAppStartingWindow: token=%s" + + " pkg=%s transferFrom=%s newTask=%b taskSwitch=%b processRunning=%b" + + " allowTaskSnapshot=%b", appToken, pkg, transferFrom, newTask, taskSwitch, + processRunning, allowTaskSnapshot); + if (mAppWindowToken == null) { Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken); return false; @@ -3215,7 +3213,7 @@ final class ActivityRecord extends ConfigurationContainer { // Window configuration changes only effect windows, so don't require a screen freeze. int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION); if (freezableConfigChanges == 0 && mAppWindowToken.okToDisplay()) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", appToken); return; } @@ -3229,11 +3227,9 @@ final class ActivityRecord extends ConfigurationContainer { if (mAppWindowToken == null) { return; } - if (DEBUG_ORIENTATION) { - Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden=" - + mAppWindowToken.isHidden() + " freezing=" - + mAppWindowToken.isFreezingScreen()); - } + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Clear freezing of %s: hidden=%b freezing=%b", appToken, + mAppWindowToken.isHidden(), mAppWindowToken.isFreezingScreen()); mAppWindowToken.stopFreezingScreen(true, force); } } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 919141c13622..6ee64f348a55 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -386,6 +386,8 @@ public class ActivityStartController { throw new IllegalArgumentException("File descriptors passed in Intent"); } + // Get the flag earlier because the intent may be modified in resolveActivity below. + final boolean componentSpecified = intent.getComponent() != null; // Don't modify the client's object! intent = new Intent(intent); @@ -409,7 +411,6 @@ public class ActivityStartController { .setCaller(caller) .setResolvedType(resolvedTypes[i]) .setActivityInfo(aInfo) - .setResultTo(resultTo) .setRequestCode(-1) .setCallingPid(callingPid) .setCallingUid(callingUid) @@ -417,7 +418,7 @@ public class ActivityStartController { .setRealCallingPid(realCallingPid) .setRealCallingUid(realCallingUid) .setActivityOptions(checkedOptions) - .setComponentSpecified(intent.getComponent() != null) + .setComponentSpecified(componentSpecified) // Top activity decides on animation being run, so we allow only for the // top one as otherwise an activity below might consume it. @@ -430,7 +431,8 @@ public class ActivityStartController { // Lock the loop to ensure the activities launched in a sequence. synchronized (mService.mGlobalLock) { for (int i = 0; i < starters.length; i++) { - final int startResult = starters[i].setOutActivity(outActivity).execute(); + final int startResult = starters[i].setResultTo(resultTo) + .setOutActivity(outActivity).execute(); if (startResult < START_SUCCESS) { // Abort by error result and recycle unused starters. for (int j = i + 1; j < starters.length; j++) { diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 66d52cc9bf5a..93c461f3add9 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -70,8 +70,9 @@ import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnte import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE; import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; @@ -131,6 +132,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils.Dump; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AttributeCache; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.animation.ClipRectLRAnimation; import com.android.server.wm.animation.ClipRectTBAnimation; import com.android.server.wm.animation.CurvedTranslateAnimation; @@ -1630,70 +1632,61 @@ public class AppTransition implements Dump { a = loadAnimationRes(lp, enter ? com.android.internal.R.anim.voice_activity_open_enter : com.android.internal.R.anim.voice_activity_open_exit); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation voice:" - + " anim=" + a + " transit=" + appTransitionToString(transit) - + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a, + appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE || transit == TRANSIT_TASK_CLOSE || transit == TRANSIT_TASK_TO_BACK)) { a = loadAnimationRes(lp, enter ? com.android.internal.R.anim.voice_activity_close_enter : com.android.internal.R.anim.voice_activity_close_exit); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation voice:" - + " anim=" + a + " transit=" + appTransitionToString(transit) - + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a, + appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) { a = createRelaunchAnimation(frame, insets); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a + " nextAppTransition=" + mNextAppTransition - + " transit=" + appTransitionToString(transit) - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", a, + mNextAppTransition, appTransitionToString(transit), + Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { a = loadAnimationRes(mNextAppTransitionPackage, enter ? mNextAppTransitionEnter : mNextAppTransitionExit); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" - + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s " + + "isEntrance=%b Callers=%s", + a, appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" - + " transit=" + appTransitionToString(transit) - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE " + + "transit=%s Callers=%s", + a, appTransitionToString(transit), Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" - + " transit=" + appTransitionToString(transit) - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL " + + "transit=%s Callers=%s", + a, appTransitionToString(transit), Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { a = createScaleUpAnimationLocked(transit, enter, frame); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" - + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s " + + "isEntrance=%s Callers=%s", + a, appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { mNextAppTransitionScaleUp = (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), frame, transit, taskId); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { - String animName = mNextAppTransitionScaleUp ? - "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; - Slog.v(TAG, "applyAnimation:" - + " anim=" + a + " nextAppTransition=" + animName - + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter - + " Callers=" + Debug.getCallers(3)); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b " + + "Callers=%s", + a, mNextAppTransitionScaleUp + ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN", + appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { mNextAppTransitionScaleUp = @@ -1701,30 +1694,27 @@ public class AppTransition implements Dump { a = createAspectScaledThumbnailEnterExitAnimationLocked( getThumbnailTransitionState(enter), uiMode, orientation, transit, frame, insets, surfaceInsets, stableInsets, freeform, taskId); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { - String animName = mNextAppTransitionScaleUp ? - "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; - Slog.v(TAG, "applyAnimation:" - + " anim=" + a + " nextAppTransition=" + animName - + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter - + " Callers=" + Debug.getCallers(3)); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b " + + "Callers=%s", + a, mNextAppTransitionScaleUp + ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP" + : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN", + appTransitionToString(transit), enter, Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) { a = loadAnimationRes("android", com.android.internal.R.anim.task_open_enter_cross_profile_apps); - Slog.v(TAG, - "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:" - + " anim=" + a + " transit=" + appTransitionToString(transit) - + " isEntrance=true" + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: " + + "anim=%s transit=%s isEntrance=true Callers=%s", + a, appTransitionToString(transit), Debug.getCallers(3)); } else if (transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE) { // In the absence of a specific adapter, we just want to keep everything stationary. a = new AlphaAnimation(1.f, 1.f); a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION); - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { - Slog.v(TAG, "applyAnimation:" - + " anim=" + a + " transit=" + appTransitionToString(transit) - + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", + a, appTransitionToString(transit), enter, Debug.getCallers(3)); } else { int animAttr = 0; switch (transit) { @@ -1787,12 +1777,11 @@ public class AppTransition implements Dump { : WindowAnimation_launchTaskBehindTargetAnimation; } a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null; - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, - "applyAnimation:" - + " anim=" + a - + " animAttr=0x" + Integer.toHexString(animAttr) - + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter - + " Callers=" + Debug.getCallers(3)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b " + + "Callers=%s", + a, animAttr, appTransitionToString(transit), enter, + Debug.getCallers(3)); } return a; } @@ -1941,8 +1930,8 @@ public class AppTransition implements Dump { } void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) { - if (DEBUG_APP_TRANSITIONS) Slog.i(TAG, "Override pending remote transitionSet=" - + isTransitionSet() + " adapter=" + remoteAnimationAdapter); + ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s", + isTransitionSet(), remoteAnimationAdapter); if (isTransitionSet()) { clear(); mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE; @@ -2214,12 +2203,11 @@ public class AppTransition implements Dump { */ boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent, @TransitionFlags int flags, boolean forceOverride) { - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:" - + " transit=" + appTransitionToString(transit) - + " " + this - + " alwaysKeepCurrent=" + alwaysKeepCurrent - + " displayId=" + mDisplayContent.getDisplayId() - + " Callers=" + Debug.getCallers(5)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d " + + "Callers=%s", + appTransitionToString(transit), this, alwaysKeepCurrent, + mDisplayContent.getDisplayId(), Debug.getCallers(5)); final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition) && transit == TRANSIT_CRASHING_ACTIVITY_CLOSE; if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet() @@ -2305,15 +2293,14 @@ public class AppTransition implements Dump { } if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty() || !dc.mChangingApps.isEmpty()) { - if (DEBUG_APP_TRANSITIONS) { - Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT." - + " displayId=" + dc.getDisplayId() - + " isTransitionSet()=" - + dc.mAppTransition.isTransitionSet() - + " mOpeningApps.size()=" + dc.mOpeningApps.size() - + " mClosingApps.size()=" + dc.mClosingApps.size() - + " mChangingApps.size()=" + dc.mChangingApps.size()); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b " + + "mOpeningApps.size()=%d mClosingApps.size()=%d " + + "mChangingApps.size()=%d", + dc.getDisplayId(), dc.mAppTransition.isTransitionSet(), + dc.mOpeningApps.size(), dc.mClosingApps.size(), + dc.mChangingApps.size()); + setTimeout(); mService.mWindowPlacerLocked.performSurfacePlacement(); } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 59f086efbc5b..20a871baada4 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -48,7 +48,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_S import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -66,6 +66,7 @@ import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.protolog.common.ProtoLog; import java.util.function.Predicate; @@ -104,7 +105,7 @@ public class AppTransitionController { } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady"); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO"); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO"); final AppTransition appTransition = mDisplayContent.mAppTransition; int transit = appTransition.getAppTransition(); if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) { @@ -348,7 +349,7 @@ public class AppTransitionController { final int appsCount = openingApps.size(); for (int i = 0; i < appsCount; i++) { AppWindowToken wtoken = openingApps.valueAt(i); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", wtoken); if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) { // This token isn't going to be animating. Add it to the list of tokens to @@ -383,7 +384,7 @@ public class AppTransitionController { for (int i = 0; i < appsCount; i++) { AppWindowToken wtoken = closingApps.valueAt(i); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", wtoken); // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not // animating? wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction); @@ -410,7 +411,7 @@ public class AppTransitionController { final int appsCount = apps.size(); for (int i = 0; i < appsCount; i++) { AppWindowToken wtoken = apps.valueAt(i); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wtoken); wtoken.cancelAnimationOnly(); wtoken.applyAnimationLocked(null, transit, true, false); wtoken.updateReportedVisibilityLocked(); @@ -445,10 +446,9 @@ public class AppTransitionController { } private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) { - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, - "Checking " + apps.size() + " opening apps (frozen=" - + mService.mDisplayFrozen + " timeout=" - + mDisplayContent.mAppTransition.isTimeout() + ")..."); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(), + mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout()); final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent( Display.DEFAULT_DISPLAY).getRotationAnimation(); @@ -463,20 +463,18 @@ public class AppTransitionController { // app transition. if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() && mDisplayContent.getDisplayRotation().needsUpdate()) { - if (DEBUG_APP_TRANSITIONS) { - Slog.v(TAG, "Delaying app transition for screen rotation animation to finish"); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Delaying app transition for screen rotation animation to finish"); return false; } for (int i = 0; i < apps.size(); i++) { AppWindowToken wtoken = apps.valueAt(i); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, - "Check opening app=" + wtoken + ": allDrawn=" - + wtoken.allDrawn + " startingDisplayed=" - + wtoken.startingDisplayed + " startingMoved=" - + wtoken.startingMoved + " isRelaunching()=" - + wtoken.isRelaunching() + " startingWindow=" - + wtoken.startingWindow); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Check opening app=%s: allDrawn=%b startingDisplayed=%b " + + "startingMoved=%b isRelaunching()=%b startingWindow=%s", + wtoken, wtoken.allDrawn, wtoken.startingDisplayed, + wtoken.startingMoved, wtoken.isRelaunching(), + wtoken.startingWindow); final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching(); @@ -496,15 +494,13 @@ public class AppTransitionController { // We also need to wait for the specs to be fetched, if needed. if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) { - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true"); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true"); return false; } if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) { - if (DEBUG_APP_TRANSITIONS) { - Slog.v(TAG, "unknownApps is not empty: " - + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage()); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s", + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage()); return false; } @@ -549,22 +545,20 @@ public class AppTransitionController { true /* ignoreHidden */); boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, - "New wallpaper target=" + wallpaperTarget - + ", oldWallpaper=" + oldWallpaper - + ", openingApps=" + openingApps - + ", closingApps=" + closingApps); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s", + wallpaperTarget, oldWallpaper, openingApps, closingApps); if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) { transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, - "New transit: " + AppTransition.appTransitionToString(transit)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "New transit: %s", AppTransition.appTransitionToString(transit)); } // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic // relies on the fact that we always execute a Keyguard transition after preparing one. else if (!isKeyguardGoingAwayTransit(transit)) { if (closingAppHasWallpaper && openingAppHasWallpaper) { - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!"); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!"); switch (transit) { case TRANSIT_ACTIVITY_OPEN: case TRANSIT_TASK_OPEN: @@ -577,16 +571,17 @@ public class AppTransitionController { transit = TRANSIT_WALLPAPER_INTRA_CLOSE; break; } - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, - "New transit: " + AppTransition.appTransitionToString(transit)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "New transit: %s", AppTransition.appTransitionToString(transit)); } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty() && !openingApps.contains(oldWallpaper.mAppToken) && closingApps.contains(oldWallpaper.mAppToken) && topClosingApp == oldWallpaper.mAppToken) { // We are transitioning from an activity with a wallpaper to one without. transit = TRANSIT_WALLPAPER_CLOSE; - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: " - + AppTransition.appTransitionToString(transit)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "New transit away from wallpaper: %s", + AppTransition.appTransitionToString(transit)); } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() && openingApps.contains(wallpaperTarget.mAppToken) && topOpeningApp == wallpaperTarget.mAppToken @@ -594,8 +589,8 @@ public class AppTransitionController { // We are transitioning from an activity without // a wallpaper to now showing the wallpaper transit = TRANSIT_WALLPAPER_OPEN; - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: " - + AppTransition.appTransitionToString(transit)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "New transit into wallpaper: %s", + AppTransition.appTransitionToString(transit)); } } return transit; @@ -722,8 +717,7 @@ public class AppTransitionController { final WindowState win = mDisplayContent.findFocusedWindow(); if (win != null) { final AppWindowToken wtoken = win.mAppToken; - if (DEBUG_APP_TRANSITIONS) - Slog.v(TAG, "Now animating app in place " + wtoken); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now animating app in place %s", wtoken); wtoken.cancelAnimation(); wtoken.applyAnimationLocked(null, transit, false, false); wtoken.updateReportedVisibilityLocked(); diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index b52ade415bd4..2b05024415b9 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -22,7 +22,7 @@ import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT; import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR; import static com.android.server.wm.AppWindowThumbnailProto.WIDTH; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; @@ -31,7 +31,6 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Point; import android.os.Binder; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Surface; import android.view.SurfaceControl; @@ -39,6 +38,7 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import java.util.function.Supplier; @@ -104,9 +104,7 @@ class AppWindowThumbnail implements Animatable { window != null ? window.mOwnerUid : Binder.getCallingUid()) .build(); - if (SHOW_TRANSACTIONS) { - Slog.i(TAG, " THUMBNAIL " + mSurfaceControl + ": CREATE"); - } + ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl); // Transfer the thumbnail to the surface drawSurface.copyFrom(mSurfaceControl); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index fc350cd900c1..266862820017 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -62,17 +62,16 @@ import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED; import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL; import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN; @@ -124,6 +123,7 @@ import com.android.server.LocalServices; import com.android.server.display.color.ColorDisplayService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.StartingSurface; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord; import com.android.server.wm.WindowManagerService.H; @@ -388,8 +388,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree removeDeadWindows(); if (startingWindow != null) { - if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting " - + win.mToken + ": first real window is shown, no animation"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s" + + ": first real window is shown, no animation", win.mToken); // If this initial window is animating, stop it -- we will do an animation to reveal // it from behind the starting window, so there is no need for it to also be doing its // own stuff. @@ -480,8 +480,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) { return; } - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this - + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "setClientHidden: %s clientHidden=%b Callers=%s", this, hideClient, + Debug.getCallers(5)); mClientHidden = hideClient; sendAppVisibilityToClients(); } @@ -507,12 +508,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return; } - if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) { - Slog.v(TAG_WM, "setAppVisibility(" - + appToken + ", visible=" + visible + "): " + appTransition - + " hidden=" + isHidden() + " hiddenRequested=" - + hiddenRequested + " Callers=" + Debug.getCallers(6)); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s", + appToken, visible, appTransition, isHidden(), hiddenRequested, + Debug.getCallers(6)); final DisplayContent displayContent = getDisplayContent(); displayContent.mOpeningApps.remove(this); @@ -573,7 +572,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree requestUpdateWallpaperIfNeeded(); - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this); mAppStopped = false; transferStartingWindowFromHiddenAboveTokenIfNeeded(); @@ -596,10 +595,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (win != null) { final AppWindowToken focusedToken = win.mAppToken; if (focusedToken != null) { - if (DEBUG_APP_TRANSITIONS) { - Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, " - + " adding " + focusedToken + " to mOpeningApps"); - } + ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, + "TRANSIT_TASK_OPEN_BEHIND, adding %s to mOpeningApps", + focusedToken); + // Force animation to be loaded. displayContent.mOpeningApps.add(focusedToken); } @@ -638,8 +637,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final AccessibilityController accessibilityController = mWmService.mAccessibilityController; boolean changed = false; - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, - "Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Changing app %s hidden=%b performLayout=%b", this, isHidden(), + performLayout); boolean runningAppAnimation = false; @@ -681,10 +681,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true); } - if (DEBUG_APP_TRANSITIONS) { - Slog.v(TAG_WM, "commitVisibility: " + this - + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "commitVisibility: %s: hidden=%b hiddenRequested=%b", this, + isHidden(), hiddenRequested); if (changed) { displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); @@ -887,7 +886,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } mRemovingFromDisplay = true; - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this); boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); @@ -903,11 +902,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree delayed = true; } - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed - + " animation=" + getAnimation() + " animating=" + isSelfAnimating()); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Removing app %s delayed=%b animation=%s animating=%b", this, delayed, + getAnimation(), isSelfAnimating()); - if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " - + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s" + + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4)); if (mStartingData != null) { removeStartingWindow(); @@ -923,8 +923,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final TaskStack stack = getStack(); if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished - if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, - "removeAppToken make exiting: " + this); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "removeAppToken make exiting: %s", this); if (stack != null) { stack.mExitingAppTokens.add(this); } @@ -944,8 +944,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final DisplayContent dc = getDisplayContent(); if (dc.mFocusedApp == this) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this - + " displayId=" + dc.getDisplayId()); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, + "Removing focused app token:%s displayId=%d", this, + dc.getDisplayId()); dc.setFocusedApp(null); mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } @@ -1009,8 +1010,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree * up of the surfaces */ void notifyAppResumed(boolean wasStopped) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped - + " " + this); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s", + wasStopped, this); mAppStopped = false; // Allow the window to turn the screen on once the app is resumed again. setCurrentLaunchCanTurnScreenOn(true); @@ -1024,7 +1025,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree * keeping alive in case they were still being used. */ void notifyAppStopped() { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this); mAppStopped = true; // Reset the last saved PiP snap fraction on app stop. mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent); @@ -1087,12 +1088,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void postWindowRemoveStartingWindowCleanup(WindowState win) { // TODO: Something smells about the code below...Is there a better way? if (startingWindow == win) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Notify removed startingWindow %s", win); removeStartingWindow(); } else if (mChildren.size() == 0) { // If this is the last window and we had requested a starting transition window, // well there is no point now. - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData"); mStartingData = null; if (mHiddenSetFromTransferredStartingWindow) { // We set the hidden state to false for the token from a transferred starting window. @@ -1103,8 +1104,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { // If this is the last window except for a starting transition window, // we need to get rid of the starting transition. - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window " - + win); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Last window, removing starting window %s", win); removeStartingWindow(); } } @@ -1113,8 +1113,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) { WindowState win = mChildren.get(winNdx); if (win.mAppDied) { - if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG, - "removeDeadWindows: " + win); + ProtoLog.w(WM_DEBUG_ADD_REMOVE, + "removeDeadWindows: %s", win); // Set mDestroying, we don't want any animation or delayed removal here. win.mDestroying = true; // Also removes child windows. @@ -1135,8 +1135,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void setWillReplaceWindows(boolean animate) { - if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, - "Marking app token " + this + " with replacing windows."); + ProtoLog.d(WM_DEBUG_ADD_REMOVE, + "Marking app token %s with replacing windows.", this); for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowState w = mChildren.get(i); @@ -1145,8 +1145,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void setWillReplaceChildWindows() { - if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this - + " with replacing child windows."); + ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Marking app token %s" + + " with replacing child windows.", this); for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowState w = mChildren.get(i); w.setWillReplaceChildWindows(); @@ -1154,8 +1154,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void clearWillReplaceWindows() { - if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, - "Resetting app token " + this + " of replacing window marks."); + ProtoLog.d(WM_DEBUG_ADD_REMOVE, + "Resetting app token %s of replacing window marks.", this); for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowState w = mChildren.get(i); @@ -1320,10 +1320,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void reparent(Task task, int position) { - if (DEBUG_ADD_REMOVE) { - Slog.i(TAG_WM, "reparent: moving app token=" + this - + " to task=" + task.mTaskId + " at " + position); - } + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving app token=%s" + + " to task=%d at %d", this, task.mTaskId, position); + if (task == null) { throw new IllegalArgumentException("reparent: could not find task"); } @@ -1339,8 +1338,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree + " belongs to a different stack than " + task); } - if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this - + " from task=" + currentTask); + ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reParentWindowToken: removing window token=%s" + + " from task=%s" , this, currentTask); final DisplayContent prevDisplayContent = getDisplayContent(); mReparenting = true; @@ -1460,9 +1459,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void startFreezingScreen() { - if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden=" - + isHidden() + " freezing=" + mFreezingScreen + " hiddenRequested=" - + hiddenRequested); + ProtoLog.i(WM_DEBUG_ORIENTATION, + "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s", + appToken, isHidden(), mFreezingScreen, hiddenRequested, + new RuntimeException().fillInStackTrace()); if (!hiddenRequested) { if (!mFreezingScreen) { mFreezingScreen = true; @@ -1486,7 +1486,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (!mFreezingScreen) { return; } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Clear freezing of %s force=%b", this, force); final int count = mChildren.size(); boolean unfrozeWindows = false; for (int i = 0; i < count; i++) { @@ -1494,7 +1495,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree unfrozeWindows |= w.onStopFreezingScreen(); } if (force || unfrozeWindows) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this); + ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this); mFreezingScreen = false; mWmService.unregisterAppFreezeListener(this); mWmService.mAppsFreezingScreen--; @@ -1545,8 +1546,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // letting windows get shown immediately without any more transitions. getDisplayContent().mSkipAppTransitionAnimation = true; - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow - + " from " + fromToken + " to " + this); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s" + + " from %s to %s", tStartingWindow, fromToken, this); final long origId = Binder.clearCallingIdentity(); try { @@ -1564,8 +1565,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree tStartingWindow.mToken = this; tStartingWindow.mAppToken = this; - if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, - "Removing starting " + tStartingWindow + " from " + fromToken); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "Removing starting %s from %s", tStartingWindow, fromToken); fromToken.removeChild(tStartingWindow); fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow); fromToken.mHiddenSetFromTransferredStartingWindow = false; @@ -1606,8 +1607,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } else if (fromToken.mStartingData != null) { // The previous app was getting ready to show a // starting window, but hasn't yet done so. Steal it! - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, - "Moving pending starting from " + fromToken + " to " + this); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Moving pending starting from %s to %s", fromToken, this); mStartingData = fromToken.mStartingData; fromToken.mStartingData = null; fromToken.startingMoved = true; @@ -1879,9 +1880,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mFreezingScreen) { showAllWindowsLocked(); stopFreezingScreen(false, true); - if (DEBUG_ORIENTATION) Slog.i(TAG, - "Setting mOrientationChangeComplete=true because wtoken " + this - + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows); + ProtoLog.i(WM_DEBUG_ORIENTATION, + "Setting mOrientationChangeComplete=true because wtoken %s " + + "numInteresting=%d numDrawn=%d", + this, mNumInterestingWindows, mNumDrawnWindows); // This will set mOrientationChangeComplete and cause a pass through layout. setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, "checkAppWindowsReadyToShow: freezingScreen"); @@ -1985,7 +1987,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree boolean isInterestingAndDrawn = false; if (!allDrawn && w.mightAffectAllDrawn()) { - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { + if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() + ", isAnimationSet=" + isSelfAnimating()); if (!w.isDrawnLw()) { @@ -2006,10 +2008,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (w.isDrawnLw()) { mNumDrawnWindows++; - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: " - + this + " w=" + w + " numInteresting=" + mNumInterestingWindows - + " freezingScreen=" + mFreezingScreen - + " mAppFreezing=" + w.mAppFreezing); + if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { + Slog.v(TAG, "tokenMayBeDrawn: " + + this + " w=" + w + " numInteresting=" + mNumInterestingWindows + + " freezingScreen=" + mFreezingScreen + + " mAppFreezing=" + w.mAppFreezing); + } isInterestingAndDrawn = true; } @@ -2125,9 +2129,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // If this is a translucent window, then don't show a starting window -- the current // effect (a full-screen opaque starting window that fades away to the real contents // when it is ready) does not work for this. - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Checking theme of starting window: 0x" + Integer.toHexString(theme)); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme); if (theme != 0) { AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, com.android.internal.R.styleable.Window, @@ -2145,11 +2147,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree com.android.internal.R.styleable.Window_windowShowWallpaper, false); final boolean windowDisableStarting = ent.array.getBoolean( com.android.internal.R.styleable.Window_windowDisablePreview, false); - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Translucent=" + windowIsTranslucent - + " Floating=" + windowIsFloating - + " ShowWallpaper=" + windowShowWallpaper); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s", + windowIsTranslucent, windowIsFloating, windowShowWallpaper); if (windowIsTranslucent) { return false; } @@ -2181,7 +2180,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return false; } - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData"); mStartingData = new SplashScreenStartingData(mWmService, pkg, theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, getMergedOverrideConfiguration()); @@ -2195,7 +2194,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return false; } - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData"); mStartingData = new SnapshotStartingData(mWmService, snapshot); scheduleAddStartingWindow(); return true; @@ -2206,7 +2205,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // want to process the message ASAP, before any other queued // messages. if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING"); mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow); } } @@ -2223,18 +2222,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mStartingData == null) { // Animation has been canceled... do nothing. - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "startingData was nulled out before handling" - + " mAddStartingWindow: " + AppWindowToken.this); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "startingData was nulled out before handling" + + " mAddStartingWindow: %s", AppWindowToken.this); return; } startingData = mStartingData; } - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s", + this, startingData); + WindowManagerPolicy.StartingSurface surface = null; try { @@ -2248,27 +2246,28 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // If the window was successfully added, then // we need to remove it. if (removed || mStartingData == null) { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Aborted starting " + AppWindowToken.this - + ": removed=" + removed + " startingData=" + mStartingData); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Aborted starting %s: removed=%b startingData=%s", + AppWindowToken.this, removed, mStartingData); + startingWindow = null; mStartingData = null; abort = true; } else { startingSurface = surface; } - if (DEBUG_STARTING_WINDOW && !abort) { - Slog.v(TAG, - "Added starting " + AppWindowToken.this + ": startingWindow=" - + startingWindow + " startingView=" + startingSurface); + if (!abort) { + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Added starting %s: startingWindow=%s startingView=%s", + AppWindowToken.this, startingWindow, startingSurface); } } if (abort) { surface.remove(); } - } else if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this); + } else { + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s", + AppWindowToken.this); } } }; @@ -2311,9 +2310,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mStartingData != null) { // Starting window has not been added yet, but it is scheduled to be added. // Go ahead and cancel the request. - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "Clearing startingData for token=" + this); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Clearing startingData for token=%s", this); mStartingData = null; } return; @@ -2327,31 +2324,28 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree startingWindow = null; startingDisplayed = false; if (surface == null) { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't " + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "startingWindow was set but startingSurface==null, couldn't " + "remove"); - } + return; } } else { - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:" - + this); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Tried to remove starting window but startingWindow was null: %s", + this); return; } - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG_WM, "Schedule remove starting " + this - + " startingWindow=" + startingWindow - + " startingView=" + startingSurface - + " Callers=" + Debug.getCallers(5)); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s" + + " startingView=%s Callers=%s", + this, startingWindow, startingSurface, Debug.getCallers(5)); + // Use the same thread to remove the window as we used to add it, as otherwise we end up // with things in the view hierarchy being called from different threads. mWmService.mAnimationHandler.post(() -> { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface); try { surface.remove(); } catch (Exception e) { @@ -2547,7 +2541,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree * Creates a layer to apply crop to an animation. */ private SurfaceControl createAnimationBoundsLayer(Transaction t) { - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.i(TAG, "Creating animation bounds layer"); + ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer"); final SurfaceControl.Builder builder = makeAnimationLeash() .setParent(getAnimationLeashParent()) .setName(getSurfaceControl() + " - animation-bounds"); @@ -2583,10 +2577,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree boolean isVoiceInteraction) { if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) { - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { - Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped." - + " atoken=" + this); - } + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: transition animation is disabled or skipped. " + + "atoken=%s", this); cancelAnimation(); return false; } @@ -2686,8 +2679,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int width = displayInfo.appWidth; final int height = displayInfo.appHeight; - if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM, - "applyAnimation: atoken=" + this); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, + "applyAnimation: atoken=%s", this); // Determine the visible rect to calculate the thumbnail clip final WindowState win = findMainWindow(); @@ -2727,9 +2720,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // screen gets the enter animation. Both appear in the mOpeningApps set. enter = false; } - if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition." - + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter - + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets); + ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, + "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s " + + "surfaceInsets=%s", + AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets); final Configuration displayConfig = displayContent.getConfiguration(); final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter, displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets, @@ -2985,7 +2979,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final GraphicBuffer thumbnailHeader = getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId); if (thumbnailHeader == null) { - if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId); + ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %d", taskId); return; } clearThumbnail(); diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index a25aab2d69a8..b4cecff728fd 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -16,15 +16,14 @@ package com.android.server.wm; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import android.graphics.Rect; -import android.util.Slog; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; import java.util.function.Supplier; @@ -58,8 +57,8 @@ public class BlackFrame { transaction.setLayer(surface, layer); transaction.setPosition(surface, left, top); transaction.show(surface); - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, - " BLACK " + surface + ": CREATE layer=" + layer); + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, + " BLACK %s: CREATE layer=%d", surface, layer); } } @@ -124,10 +123,7 @@ public class BlackFrame { SurfaceControl.Transaction t = mTransactionFactory.get(); for (int i = 0; i < mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - Slog.i(TAG_WM, - " BLACK " + mBlackSurfaces[i].surface + ": DESTROY"); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " BLACK %s: DESTROY", mBlackSurfaces[i].surface); t.remove(mBlackSurfaces[i].surface); mBlackSurfaces[i] = null; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 348c8b47c414..6d9a00804e32 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -59,11 +59,10 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -100,24 +99,21 @@ import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; import static com.android.server.wm.DisplayContentProto.STACKS; import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE; @@ -133,7 +129,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIG import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT; import static com.android.server.wm.WindowManagerService.dipToPixel; -import static com.android.server.wm.WindowManagerService.logSurface; import static com.android.server.wm.WindowState.EXCLUSION_LEFT; import static com.android.server.wm.WindowState.EXCLUSION_RIGHT; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; @@ -173,6 +168,7 @@ import android.os.UserHandle; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Slog; +import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayCutout; @@ -202,6 +198,7 @@ import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AnimationThread; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.utils.DisplayRotationUtil; import com.android.server.wm.utils.RotationCache; import com.android.server.wm.utils.WmDisplayCutout; @@ -442,11 +439,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** A collection of windows that provide tap exclude regions inside of them. */ final ArraySet<WindowState> mTapExcludeProvidingWindows = new ArraySet<>(); - private boolean mHaveBootMsg = false; - private boolean mHaveApp = false; - private boolean mHaveWallpaper = false; - private boolean mHaveKeyguard = true; - private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList(); private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult = @@ -599,8 +591,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> { final AppWindowToken focusedApp = mFocusedApp; - if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w - + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys()); + ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b", + w, w.mAttrs.flags, w.canReceiveKeys()); if (!w.canReceiveKeys()) { return false; @@ -610,22 +602,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // If this window's application has been removed, just skip it. if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) { - if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because " - + (wtoken.removed ? "removed" : "sendingToBottom")); + ProtoLog.v(WM_DEBUG_FOCUS, "Skipping %s because %s", wtoken, + (wtoken.removed ? "removed" : "sendingToBottom")); return false; } if (focusedApp == null) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null" - + " using new focus @ " + w); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, + "findFocusedWindow: focusedApp=null using new focus @ %s", w); mTmpWindow = w; return true; } if (!focusedApp.windowsAreFocusable()) { // Current focused app windows aren't focusable... - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not" - + " focusable using new focus @ " + w); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: focusedApp windows not" + + " focusable using new focus @ %s", w); mTmpWindow = w; return true; } @@ -635,14 +627,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) { if (focusedApp.compareTo(wtoken) > 0) { // App stack below focused app stack. No focus for you!!! - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, - "findFocusedWindow: Reached focused app=" + focusedApp); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, + "findFocusedWindow: Reached focused app=%s", focusedApp); mTmpWindow = null; return true; } } - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: Found new focus @ %s", w); mTmpWindow = w; return true; }; @@ -1334,7 +1326,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo forAllWindows(w -> { if (w.mHasSurface && !rotateSeamlessly) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Set mOrientationChanging of %s", w); w.setOrientationChanging(true); mWmService.mRoot.mOrientationChangeComplete = false; w.mLastFreezeDuration = 0; @@ -1998,8 +1990,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mWmService.mDisplayFrozen) { if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId - + " is frozen, return " + mLastWindowForcedOrientation); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Display id=%d is frozen, return %d", mDisplayId, + mLastWindowForcedOrientation); // If the display is frozen, some activities may be in the middle of restarting, and // thus have removed their old window. If the window has the flag to hide the lock // screen, then the lock screen can re-appear and inflict its own orientation on us. @@ -2011,8 +2004,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // window. We don't want to check the show when locked window directly though as // things aren't stable while the display is frozen, for example the window could be // momentarily unavailable due to activity relaunch. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId - + " is frozen while keyguard locked, return " + getLastOrientation()); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Display id=%d is frozen while keyguard locked, return %d", + mDisplayId, getLastOrientation()); return getLastOrientation(); } } else { @@ -2872,7 +2866,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */); if (mTmpWindow == null) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows."); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows."); return null; } return mTmpWindow; @@ -2918,11 +2912,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget(); } - if (DEBUG_FOCUS_LIGHT || DEBUG) { - Slog.v(TAG_WM, "Changing focus from " - + mCurrentFocus + " to " + newFocus + " displayId=" + getDisplayId() - + " Callers=" + Debug.getCallers(4)); - } + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s", + mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4)); final WindowState oldFocus = mCurrentFocus; mCurrentFocus = newFocus; mLosingFocus.remove(newFocus); @@ -3059,7 +3050,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): " + w + " surface=" + wsa.mSurfaceController + " token=" + w.mAppToken); - if (SHOW_TRANSACTIONS) logSurface(w, "LEAK DESTROY", false); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE LEAK DESTROY: %s", w); wsa.destroySurface(); mTmpWindow = w; } @@ -3354,34 +3345,38 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo }, true /* traverseTopToBottom */); } - boolean checkWaitingForWindows() { + /** @return {@code true} if there is window to wait before enabling the screen. */ + boolean shouldWaitForSystemDecorWindowsOnBoot() { + if (!isDefaultDisplay && !supportsSystemDecorations()) { + // Nothing to wait because the secondary display doesn't support system decorations, + // there is no wallpaper, keyguard (status bar) or application (home) window to show + // during booting. + return false; + } - mHaveBootMsg = false; - mHaveApp = false; - mHaveWallpaper = false; - mHaveKeyguard = true; + final SparseBooleanArray drawnWindowTypes = new SparseBooleanArray(); + // Presuppose keyguard is drawn because if its window isn't attached, we don't know if it + // wants to be shown or hidden, then it should not delay enabling the screen. + drawnWindowTypes.put(TYPE_STATUS_BAR, true); - final WindowState visibleWindow = getWindow(w -> { - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + final WindowState visibleNotDrawnWindow = getWindow(w -> { + if (w.mViewVisibility == View.VISIBLE && !w.mObscured && !w.isDrawnLw()) { return true; } if (w.isDrawnLw()) { - if (w.mAttrs.type == TYPE_BOOT_PROGRESS) { - mHaveBootMsg = true; - } else if (w.mAttrs.type == TYPE_APPLICATION - || w.mAttrs.type == TYPE_DRAWN_APPLICATION) { - mHaveApp = true; - } else if (w.mAttrs.type == TYPE_WALLPAPER) { - mHaveWallpaper = true; - } else if (w.mAttrs.type == TYPE_STATUS_BAR) { - mHaveKeyguard = mWmService.mPolicy.isKeyguardDrawnLw(); + final int type = w.mAttrs.type; + if (type == TYPE_BOOT_PROGRESS || type == TYPE_BASE_APPLICATION + || type == TYPE_WALLPAPER) { + drawnWindowTypes.put(type, true); + } else if (type == TYPE_STATUS_BAR) { + drawnWindowTypes.put(TYPE_STATUS_BAR, mWmService.mPolicy.isKeyguardDrawnLw()); } } return false; }); - if (visibleWindow != null) { - // We have a visible window. + if (visibleNotDrawnWindow != null) { + // Wait for the visible window to be drawn. return true; } @@ -3393,23 +3388,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo com.android.internal.R.bool.config_checkWallpaperAtBoot) && !mWmService.mOnlyCore; - if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, - "******** booted=" + mWmService.mSystemBooted - + " msg=" + mWmService.mShowingBootMessages - + " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp - + " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled - + " haveKeyguard=" + mHaveKeyguard); + final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS); + final boolean haveApp = drawnWindowTypes.get(TYPE_BASE_APPLICATION); + final boolean haveWallpaper = drawnWindowTypes.get(TYPE_WALLPAPER); + final boolean haveKeyguard = drawnWindowTypes.get(TYPE_STATUS_BAR); + + ProtoLog.i(WM_DEBUG_SCREEN_ON, + "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b " + + "wallEnabled=%b haveKeyguard=%b", + mWmService.mSystemBooted, mWmService.mShowingBootMessages, haveBootMsg, + haveApp, haveWallpaper, wallpaperEnabled, haveKeyguard); // If we are turning on the screen to show the boot message, don't do it until the boot // message is actually displayed. - if (!mWmService.mSystemBooted && !mHaveBootMsg) { + if (!mWmService.mSystemBooted && !haveBootMsg) { return true; } // If we are turning on the screen after the boot is completed normally, don't do so until // we have the application and wallpaper. if (mWmService.mSystemBooted - && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) { + && ((!haveApp && !haveKeyguard) || (wallpaperEnabled && !haveWallpaper))) { return true; } @@ -4235,8 +4234,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // associated with it will be removed as soon as their animations are // complete. cancelAnimation(); - if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, - "performLayout: App token exiting now removed" + token); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "performLayout: App token exiting now removed %s", token); token.removeIfPossible(); } } @@ -4266,15 +4265,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int orientation = super.getOrientation(); if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "App is requesting an orientation, return " + orientation - + " for display id=" + mDisplayId); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "App is requesting an orientation, return %d for display id=%d", + orientation, mDisplayId); return orientation; } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "No app is requesting an orientation, return " + getLastOrientation() - + " for display id=" + mDisplayId); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "No app is requesting an orientation, return %d for display id=%d", + getLastOrientation(), mDisplayId); // The next app has not been requested to be visible, so we keep the current orientation // to prevent freezing/unfreezing the display too early. return getLastOrientation(); @@ -4511,8 +4510,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return SCREEN_ORIENTATION_UNSET; } } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req - + " for display id=" + mDisplayId); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "%s forcing orientation to %d for display id=%d", win, req, + mDisplayId); return (mLastWindowForcedOrientation = req); } @@ -4767,10 +4767,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void executeAppTransition() { if (mAppTransition.isTransitionSet()) { - if (DEBUG_APP_TRANSITIONS) { - Slog.w(TAG_WM, "Execute app transition: " + mAppTransition + ", displayId: " - + mDisplayId + " Callers=" + Debug.getCallers(5)); - } + ProtoLog.w(WM_DEBUG_APP_TRANSITIONS, + "Execute app transition: %s, displayId: %d Callers=%s", + mAppTransition, mDisplayId, Debug.getCallers(5)); mAppTransition.setReady(); mWmService.mWindowPlacerLocked.requestTraversal(); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 10d48c4d5282..7be4dbd99766 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -98,9 +98,9 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -168,6 +168,7 @@ import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; import com.android.server.policy.WindowOrientationListener; +import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.utils.InsetUtils; @@ -765,19 +766,19 @@ public class DisplayPolicy { /** Return false if it is not ready to turn on. */ public boolean finishScreenTurningOn() { synchronized (mLock) { - if (DEBUG_SCREEN_ON) Slog.d(TAG, - "finishScreenTurningOn: mAwake=" + mAwake - + ", mScreenOnEarly=" + mScreenOnEarly - + ", mScreenOnFully=" + mScreenOnFully - + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete - + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete); + ProtoLog.d(WM_DEBUG_SCREEN_ON, + "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, " + + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, " + + "mWindowManagerDrawComplete=%b", + mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete, + mWindowManagerDrawComplete); if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete || (mAwake && !mKeyguardDrawComplete)) { return false; } - if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on..."); + ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on..."); mScreenOnListener = null; mScreenOnFully = true; } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index f08b4fc0fe91..414e496ae57e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -23,8 +23,8 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; @@ -58,6 +58,7 @@ import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowOrientationListener; +import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.PrintWriter; @@ -399,7 +400,7 @@ public class DisplayRotation { if (mDeferredRotationPauseCount > 0) { // Rotation updates have been paused temporarily. Defer the update until updates // have been resumed. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused."); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused."); return false; } @@ -409,14 +410,14 @@ public class DisplayRotation { // Rotation updates cannot be performed while the previous rotation change animation // is still in progress. Skip this update. We will try updating again after the // animation is finished and the display is unfrozen. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress."); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress."); return false; } if (mService.mDisplayFrozen) { // Even if the screen rotation animation has finished (e.g. isAnimating returns // false), there is still some time where we haven't yet unfrozen the display. We // also need to abort rotation here. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, + ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, still finishing previous rotation"); return false; } @@ -424,30 +425,30 @@ public class DisplayRotation { if (!mService.mDisplayEnabled) { // No point choosing a rotation if the display is not enabled. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled."); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled."); return false; } final int oldRotation = mRotation; final int lastOrientation = mLastOrientation; final int rotation = rotationForOrientation(lastOrientation, oldRotation); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id=" - + displayId + " based on lastOrientation=" + lastOrientation - + " and oldRotation=" + oldRotation); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Computed rotation=%d for display id=%d based on lastOrientation=%d and " + + "oldRotation=%d", + rotation, displayId, lastOrientation, oldRotation); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId - + " selected orientation " + lastOrientation - + ", got rotation " + rotation); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Display id=%d selected orientation %d, got rotation %d", displayId, + lastOrientation, rotation); if (oldRotation == rotation) { // No change. return false; } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId - + " rotation changed to " + rotation - + " from " + oldRotation - + ", lastOrientation=" + lastOrientation); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Display id=%d rotation changed to %d from %d, lastOrientation=%d", + displayId, rotation, oldRotation, lastOrientation); if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) { mDisplayContent.mWaitingForConfig = true; @@ -551,9 +552,8 @@ public class DisplayRotation { mSeamlessRotationCount--; } if (mSeamlessRotationCount == 0) { - if (DEBUG_ORIENTATION) { - Slog.i(TAG, "Performing post-rotate rotation after seamless rotation"); - } + ProtoLog.i(WM_DEBUG_ORIENTATION, + "Performing post-rotate rotation after seamless rotation"); // Finish seamless rotation. mRotatingSeamlessly = false; @@ -844,11 +844,12 @@ public class DisplayRotation { // Could have been invoked due to screen turning on or off or // change of the currently visible window's orientation. - if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly - + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation - + ", orientationSensorEnabled=" + mOrientationListener.mEnabled - + ", keyguardDrawComplete=" + keyguardDrawComplete - + ", windowManagerDrawComplete=" + windowManagerDrawComplete); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, " + + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, " + + "windowManagerDrawComplete=%b", + screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled, + keyguardDrawComplete, windowManagerDrawComplete); boolean disable = true; // Note: We postpone the rotating of the screen until the keyguard as well as the @@ -952,14 +953,11 @@ public class DisplayRotation { */ @VisibleForTesting int rotationForOrientation(int orientation, int lastRotation) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "rotationForOrientation(orient=" - + orientation + ", last=" + lastRotation - + "); user=" + mUserRotation + " " - + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED - ? "USER_ROTATION_LOCKED" : "") + ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s", + orientation, lastRotation, mUserRotation, + mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED + ? "USER_ROTATION_LOCKED" : "" ); - } if (isFixedToUserRotation()) { return mUserRotation; @@ -1059,11 +1057,19 @@ public class DisplayRotation { preferredRotation = lastRotation; } } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED - && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { - // Apply rotation lock. Does not apply to NOSENSOR. + && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE + && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) { + // Apply rotation lock. Does not apply to NOSENSOR or specific rotations. // The idea is that the user rotation expresses a weak preference for the direction // of gravity and as NOSENSOR is never affected by gravity, then neither should // NOSENSOR be affected by rotation lock (although it will be affected by docks). + // Also avoid setting user rotation when app has preference over one particular rotation + // to avoid leaving the rotation to the reverse of it which has the compatible + // orientation, but isn't what app wants, when the user rotation is the reverse of the + // preferred rotation. preferredRotation = mUserRotation; } else { // No overriding preference. @@ -1372,7 +1378,7 @@ public class DisplayRotation { @Override public void onProposedRotationChanged(int rotation) { - if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation); + ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation); Runnable r = mRunnableCache.get(rotation, null); if (r == null) { r = new UpdateRunnable(rotation); @@ -1385,14 +1391,14 @@ public class DisplayRotation { public void enable(boolean clearCurrentRotation) { super.enable(clearCurrentRotation); mEnabled = true; - if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners"); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners"); } @Override public void disable() { super.disable(); mEnabled = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners"); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners"); } } diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 3c616945f762..34820acfeccc 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -19,10 +19,10 @@ package com.android.server.wm; import static com.android.server.wm.DragDropController.MSG_ANIMATION_END; import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT; import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.Animator; @@ -58,6 +58,7 @@ import android.view.animation.Interpolator; import com.android.internal.view.IDragAndDropPermissions; import com.android.server.LocalServices; +import com.android.server.protolog.common.ProtoLog; import java.util.ArrayList; @@ -300,9 +301,7 @@ class DragState { mDragWindowHandle.frameBottom = mDisplaySize.y; // Pause rotations before a drag. - if (DEBUG_ORIENTATION) { - Slog.d(TAG_WM, "Pausing rotation during drag"); - } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during drag"); mDisplayContent.getDisplayRotation().pause(); } @@ -319,9 +318,7 @@ class DragState { mDragApplicationHandle = null; // Resume rotations after a drag. - if (DEBUG_ORIENTATION) { - Slog.d(TAG_WM, "Resuming rotation after drag"); - } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after drag"); mDisplayContent.getDisplayRotation().resume(); } } @@ -499,10 +496,9 @@ class DragState { Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked"); } mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply(); - if (SHOW_TRANSACTIONS) { - Slog.i(TAG_WM, " DRAG " + mSurfaceControl + ": pos=(" + (int) (x - mThumbOffsetX) + "," - + (int) (y - mThumbOffsetY) + ")"); - } + ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl, + (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY)); + notifyLocationLocked(x, y); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 8e0531ce3652..932b4fac4592 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -26,7 +26,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLP import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -49,6 +49,7 @@ import android.view.SurfaceControl; import com.android.server.AnimationThread; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.Set; @@ -331,9 +332,7 @@ final class InputMonitor { * Layer assignment is assumed to be complete by the time this is called. */ public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) { - if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) { - Slog.d(TAG_WM, "Input focus has changed to " + newWindow); - } + ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s", newWindow); if (newWindow != mInputFocus) { if (newWindow != null && newWindow.canReceiveKeys()) { diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java index 3db6dcf07abf..b7184a5e83d5 100644 --- a/services/core/java/com/android/server/wm/InsetsControlTarget.java +++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java @@ -16,9 +16,21 @@ package com.android.server.wm; +import android.inputmethodservice.InputMethodService; +import android.view.WindowInsets.Type.InsetType; + /** * Generalization of an object that can control insets state. */ interface InsetsControlTarget { void notifyInsetsControlChanged(); + + /** + * Instructs the control target to show inset sources. + * + * @param types to specify which types of insets source window should be shown. + * @param fromIme {@code true} if IME show request originated from {@link InputMethodService}. + */ + default void showInsets(@InsetType int types, boolean fromIme) { + } } diff --git a/services/core/java/com/android/server/wm/ProtoLogGroup.java b/services/core/java/com/android/server/wm/ProtoLogGroup.java index 313ccebc778d..f5a188402ce6 100644 --- a/services/core/java/com/android/server/wm/ProtoLogGroup.java +++ b/services/core/java/com/android/server/wm/ProtoLogGroup.java @@ -27,8 +27,38 @@ import com.android.server.protolog.common.ProtoLog; * must be included in services.core.wm.protologgroups build target. */ public enum ProtoLogGroup implements IProtoLogGroup { - GENERIC_WM(true, true, false, "WindowManager"), - + WM_ERROR(true, true, true, Consts.TAG_WM), + WM_DEBUG_ORIENTATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_FOCUS_LIGHT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_BOOT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_RESIZE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_SHOW_SURFACE_ALLOC(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_APP_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_APP_TRANSITIONS_ANIM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_RECENTS_ANIMATIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_DRAW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_REMOTE_ANIMATIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_SCREEN_ON(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_KEEP_SCREEN_ON(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_WINDOW_MOVEMENT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagetProtoLogTest"); private final boolean mEnabled; @@ -95,4 +125,11 @@ public enum ProtoLogGroup implements IProtoLogGroup { "Test completed successfully: %b %d %o %x %e %g %f %% %s.", true, 1, 2, 3, 0.4, 0.5, 0.6, "ok"); } + + private static class Consts { + private static final String TAG_WM = "WindowManager"; + + private static final boolean ENABLE_DEBUG = false; + private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true; + } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 5cabbd97b1f7..31f4584cded9 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -28,10 +28,10 @@ import static android.view.WindowManager.TRANSIT_NONE; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.BoundsAnimationController.BOUNDS; import static com.android.server.wm.BoundsAnimationController.FADE_IN; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; import android.annotation.Nullable; import android.app.ActivityOptions; @@ -42,6 +42,7 @@ import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; /** @@ -51,7 +52,6 @@ import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallback class RecentsAnimation implements RecentsAnimationCallbacks, ActivityDisplay.OnStackOrderChangedListener { private static final String TAG = RecentsAnimation.class.getSimpleName(); - private static final boolean DEBUG = DEBUG_RECENTS_ANIMATIONS; private final ActivityTaskManagerService mService; private final ActivityStackSupervisor mStackSupervisor; @@ -101,7 +101,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, * is updated to the current one. */ void preloadRecentsActivity() { - if (DEBUG) Slog.d(TAG, "Preload recents with " + mTargetIntent); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s", + mTargetIntent); ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); @@ -116,7 +117,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // keeps the original stopped state. targetActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */, true /* ignoreVisibility */); - if (DEBUG) Slog.d(TAG, "Updated config=" + targetActivity.getConfiguration()); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Updated config=%s", + targetActivity.getConfiguration()); } } else { // Create the activity record. Because the activity is invisible, this doesn't really @@ -131,7 +133,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } if (!targetActivity.attachedToProcess()) { - if (DEBUG) Slog.d(TAG, "Real start recents"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Real start recents"); mStackSupervisor.startSpecificActivityLocked(targetActivity, false /* andResume */, false /* checkConfig */); // Make sure the activity won't be involved in transition. @@ -155,7 +157,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) { - if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + mTargetIntent); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent); Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity"); // TODO(multi-display) currently only support recents animation in default display. @@ -163,8 +165,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent; if (!mWindowManager.canStartRecentsAnimation()) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); - if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition=" - + dc.mAppTransition.getAppTransition()); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "Can't start recents animation, nextAppTransition=%s", + dc.mAppTransition.getAppTransition()); return; } @@ -178,7 +181,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mRestoreTargetBehindStack = display.getStackAbove(targetStack); if (mRestoreTargetBehindStack == null) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); - if (DEBUG) Slog.d(TAG, "No stack above target stack=" + targetStack); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "No stack above target stack=%s", targetStack); return; } } @@ -201,8 +205,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, if (hasExistingActivity) { // Move the recents activity into place for the animation if it is not top most mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack); - if (DEBUG) Slog.d(TAG, "Moved stack=" + targetStack + " behind stack=" - + mDefaultDisplay.getStackAbove(targetStack)); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s", + targetStack, mDefaultDisplay.getStackAbove(targetStack)); // If there are multiple tasks in the target stack (ie. the home stack, with 3p // and default launchers coexisting), then move the task to the top as a part of @@ -220,17 +224,15 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mTargetActivityType); targetActivity = getTargetActivity(targetStack); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack); - if (DEBUG) { - Slog.d(TAG, "Moved stack=" + targetStack + " behind stack=" - + mDefaultDisplay.getStackAbove(targetStack)); - } + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s", + targetStack, mDefaultDisplay.getStackAbove(targetStack)); mWindowManager.prepareAppTransition(TRANSIT_NONE, false); mWindowManager.executeAppTransition(); // TODO: Maybe wait for app to draw in this particular case? - if (DEBUG) Slog.d(TAG, "Started intent=" + mTargetIntent); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Started intent=%s", mTargetIntent); } // Mark the target activity as launch-behind to bump its visibility for the @@ -268,9 +270,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode, boolean sendUserLeaveHint) { synchronized (mService.mGlobalLock) { - if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller=" - + mWindowManager.getRecentsAnimationController() - + " reorderMode=" + reorderMode); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "onAnimationFinished(): controller=%s reorderMode=%d", + mWindowManager.getRecentsAnimationController(), reorderMode); // Unregister for stack order changes mDefaultDisplay.unregisterStackOrderChangedListener(this); @@ -308,9 +310,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks, final ActivityRecord targetActivity = targetStack != null ? targetStack.isInStackLocked(mLaunchedTargetActivity) : null; - if (DEBUG) Slog.d(TAG, "onAnimationFinished(): targetStack=" + targetStack - + " targetActivity=" + targetActivity - + " mRestoreTargetBehindStack=" + mRestoreTargetBehindStack); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "onAnimationFinished(): targetStack=%s targetActivity=%s " + + "mRestoreTargetBehindStack=%s", + targetStack, targetActivity, mRestoreTargetBehindStack); if (targetActivity == null) { return; } @@ -333,25 +336,28 @@ class RecentsAnimation implements RecentsAnimationCallbacks, targetStack.moveToFront("RecentsAnimation.onAnimationFinished()"); } - if (DEBUG) { + if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { final ActivityStack topStack = getTopNonAlwaysOnTopStack(); if (topStack != targetStack) { - Slog.w(TAG, "Expected target stack=" + targetStack - + " to be top most but found stack=" + topStack); + ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, + "Expected target stack=%s" + + " to be top most but found stack=%s", + targetStack, topStack); } } } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){ // Restore the target stack to its previous position final ActivityDisplay display = targetActivity.getDisplay(); display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack); - if (DEBUG) { + if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { final ActivityStack aboveTargetStack = mDefaultDisplay.getStackAbove(targetStack); if (mRestoreTargetBehindStack != null && aboveTargetStack != mRestoreTargetBehindStack) { - Slog.w(TAG, "Expected target stack=" + targetStack - + " to restored behind stack=" + mRestoreTargetBehindStack - + " but it is behind stack=" + aboveTargetStack); + ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, + "Expected target stack=%s to restored behind stack=%s but" + + " it is behind stack=%s", + targetStack, mRestoreTargetBehindStack, aboveTargetStack); } } } else { @@ -402,7 +408,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, @Override public void onStackOrderChanged(ActivityStack stack) { - if (DEBUG) Slog.d(TAG, "onStackOrderChanged(): stack=" + stack); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack); if (mDefaultDisplay.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) { // The stack is not visible, so ignore this change return; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 795a2ca67ac3..bd27905e1a0f 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -29,8 +29,8 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_W import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM; import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.BoundsAnimationController.FADE_IN; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; import android.annotation.IntDef; @@ -57,6 +57,7 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; +import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; @@ -65,6 +66,7 @@ import com.google.android.collect.Sets; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.stream.Collectors; /** * Controls a single instance of the remote driven recents animation. In particular, this allows @@ -178,8 +180,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public TaskSnapshot screenshotTask(int taskId) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):" - + " mCanceled=" + mCanceled); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "screenshotTask(%d): mCanceled=%b", taskId, mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -208,8 +210,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):" - + " mCanceled=" + mCanceled); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -250,8 +252,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void setInputConsumerEnabled(boolean enabled) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):" - + " mCanceled=" + mCanceled); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "setInputConsumerEnabled(%s): mCanceled=%b", enabled, mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -392,8 +394,8 @@ public class RecentsAnimationController implements DeathRecipient { final AppWindowToken recentsComponentAppToken = targetStack.getTopChild().getTopFullscreenAppToken(); if (recentsComponentAppToken != null) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp(" - + recentsComponentAppToken.getName() + ")"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "setHomeApp(%s)", recentsComponentAppToken.getName()); mTargetAppToken = recentsComponentAppToken; if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) { mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -418,7 +420,7 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName()); final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task, isRecentTaskInvisible); task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */); @@ -429,8 +431,8 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting void removeAnimation(TaskAnimationAdapter taskAdapter) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation(" - + taskAdapter.mTask.mTaskId + ")"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "removeAnimation(%d)", taskAdapter.mTask.mTaskId); taskAdapter.mTask.setCanAffectSystemUiFlags(true); taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter); mPendingAnimations.remove(taskAdapter); @@ -438,14 +440,14 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeWallpaperAnimation()"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeWallpaperAnimation()"); wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter); mPendingWallpaperAnimations.remove(wallpaperAdapter); } void startAnimation() { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart - + " mCanceled=" + mCanceled); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "startAnimation(): mPendingStart=%b mCanceled=%b", mPendingStart, mCanceled); if (!mPendingStart || mCanceled) { // Skip starting if we've already started or canceled the animation return; @@ -483,13 +485,10 @@ public class RecentsAnimationController implements DeathRecipient { } mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets, minimizedHomeBounds); - if (DEBUG_RECENTS_ANIMATIONS) { - Slog.d(TAG, "startAnimation(): Notify animation start:"); - for (int i = 0; i < mPendingAnimations.size(); i++) { - final Task task = mPendingAnimations.get(i).mTask; - Slog.d(TAG, "\t" + task.mTaskId); - } - } + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "startAnimation(): Notify animation start: %s", + mPendingAnimations.stream() + .map(anim->anim.mTask.mTaskId).collect(Collectors.toList())); } catch (RemoteException e) { Slog.e(TAG, "Failed to start recents animation", e); } @@ -513,7 +512,7 @@ public class RecentsAnimationController implements DeathRecipient { } private RemoteAnimationTarget[] createWallpaperAnimations() { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()"); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "createWallpaperAnimations()"); return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L, adapter -> { synchronized (mService.mGlobalLock) { @@ -533,7 +532,7 @@ public class RecentsAnimationController implements DeathRecipient { } private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "cancelAnimation(): reason=%s", reason); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { // We've already canceled the animation @@ -627,9 +626,7 @@ public class RecentsAnimationController implements DeathRecipient { mRecentScreenshotAnimator = new SurfaceAnimator( animatable, () -> { - if (DEBUG_RECENTS_ANIMATIONS) { - Slog.d(TAG, "mRecentScreenshotAnimator finish"); - } + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish"); mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */); }, mService); mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator); @@ -637,9 +634,10 @@ public class RecentsAnimationController implements DeathRecipient { } void cleanupAnimation(@ReorderMode int reorderMode) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, - "cleanupAnimation(): Notify animation finished mPendingAnimations=" - + mPendingAnimations.size() + " reorderMode=" + reorderMode); + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "cleanupAnimation(): Notify animation finished mPendingAnimations=%d " + + "reorderMode=%d", + mPendingAnimations.size(), reorderMode); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i); if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) { diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 87bda4a545e1..2b2ae927dd96 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -17,9 +17,8 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapterProto.REMOTE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -39,6 +38,8 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.util.FastPrintWriter; +import com.android.server.protolog.ProtoLogImpl; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; @@ -51,7 +52,6 @@ import java.util.ArrayList; */ class RemoteAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME - || (DEBUG_REMOTE_ANIMATIONS && !DEBUG_APP_TRANSITIONS) ? "RemoteAnimationController" : TAG_WM; private static final long TIMEOUT_MS = 2000; @@ -86,8 +86,8 @@ class RemoteAnimationController implements DeathRecipient { */ RemoteAnimationRecord createRemoteAnimationRecord(AppWindowToken appWindowToken, Point position, Rect stackBounds, Rect startBounds) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimationAdapter(): token=" - + appWindowToken); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): token=%s", + appWindowToken); final RemoteAnimationRecord adapters = new RemoteAnimationRecord(appWindowToken, position, stackBounds, startBounds); mPendingAnimations.add(adapters); @@ -98,11 +98,11 @@ class RemoteAnimationController implements DeathRecipient { * Called when the transition is ready to be started, and all leashes have been set up. */ void goodToGo() { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo()"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()"); if (mPendingAnimations.isEmpty() || mCanceled) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): Animation finished already," - + " canceled=" + mCanceled - + " mPendingAnimations=" + mPendingAnimations.size()); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, + "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d", + mCanceled, mPendingAnimations.size()); onAnimationFinished(); return; } @@ -115,7 +115,7 @@ class RemoteAnimationController implements DeathRecipient { // Create the app targets final RemoteAnimationTarget[] appTargets = createAppAnimations(); if (appTargets.length == 0) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): No apps to animate"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): No apps to animate"); onAnimationFinished(); return; } @@ -131,8 +131,8 @@ class RemoteAnimationController implements DeathRecipient { Slog.e(TAG, "Failed to start remote animation", e); onAnimationFinished(); } - if (DEBUG_REMOTE_ANIMATIONS) { - Slog.d(TAG, "startAnimation(): Notify animation start:"); + if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) { + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:"); writeStartDebugStatement(); } }); @@ -140,7 +140,7 @@ class RemoteAnimationController implements DeathRecipient { } void cancelAnimation(String reason) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { return; @@ -152,28 +152,28 @@ class RemoteAnimationController implements DeathRecipient { } private void writeStartDebugStatement() { - Slog.i(TAG, "Starting remote animation"); + ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Starting remote animation"); final StringWriter sw = new StringWriter(); final FastPrintWriter pw = new FastPrintWriter(sw); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { mPendingAnimations.get(i).mAdapter.dump(pw, ""); } pw.close(); - Slog.i(TAG, sw.toString()); + ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "%s", sw.toString()); } private RemoteAnimationTarget[] createAppAnimations() { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAppAnimations()"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAppAnimations()"); final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final RemoteAnimationRecord wrappers = mPendingAnimations.get(i); final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget(); if (target != null) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tAdd token=" + wrappers.mAppWindowToken); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd token=%s", wrappers.mAppWindowToken); targets.add(target); } else { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tRemove token=" - + wrappers.mAppWindowToken); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove token=%s", + wrappers.mAppWindowToken); // We can't really start an animation but we still need to make sure to finish the // pending animation that was started by SurfaceAnimator @@ -194,7 +194,7 @@ class RemoteAnimationController implements DeathRecipient { } private RemoteAnimationTarget[] createWallpaperAnimations() { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()"); return WallpaperAnimationAdapter.startWallpaperAnimations(mService, mRemoteAnimationAdapter.getDuration(), mRemoteAnimationAdapter.getStatusBarTransitionDelay(), @@ -207,15 +207,15 @@ class RemoteAnimationController implements DeathRecipient { } private void onAnimationFinished() { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): mPendingAnimations=" - + mPendingAnimations.size()); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d", + mPendingAnimations.size()); mHandler.removeCallbacks(mTimeoutRunnable); synchronized (mService.mGlobalLock) { unlinkToDeathOfRunner(); releaseFinishedCallback(); mService.openSurfaceTransaction(); try { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): Notify animation finished:"); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final RemoteAnimationRecord adapters = mPendingAnimations.get(i); @@ -228,14 +228,14 @@ class RemoteAnimationController implements DeathRecipient { .onAnimationFinished(adapters.mThumbnailAdapter); } mPendingAnimations.remove(i); - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tapp=" + adapters.mAppWindowToken); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tapp=%s", adapters.mAppWindowToken); } for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) { final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i); adapter.getLeashFinishedCallback().onAnimationFinished(adapter); mPendingWallpaperAnimations.remove(i); - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\twallpaper=" + adapter.getToken()); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken()); } } catch (Exception e) { Slog.e(TAG, "Failed to finish remote animation", e); @@ -245,7 +245,7 @@ class RemoteAnimationController implements DeathRecipient { } } setRunningRemoteAnimation(false); - if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation"); + ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation"); } private void invokeAnimationCancelled() { @@ -306,7 +306,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void onAnimationFinished() throws RemoteException { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-onAnimationFinished(): mOuter=" + mOuter); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter); final long token = Binder.clearCallingIdentity(); try { if (mOuter != null) { @@ -326,7 +326,7 @@ class RemoteAnimationController implements DeathRecipient { * to prevent memory leak. */ void release() { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-release(): mOuter=" + mOuter); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter); mOuter = null; } }; @@ -420,7 +420,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, OnAnimationFinishedCallback finishCallback) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); // Restore z-layering, position and stack crop until client has a chance to modify it. t.setLayer(animationLeash, mRecord.mAppWindowToken.getPrefixOrderIndex()); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 4365d0325545..78fcb37aacd1 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -29,20 +29,19 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.RootWindowContainerProto.DISPLAYS; import static com.android.server.wm.RootWindowContainerProto.WINDOWS; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT; @@ -50,7 +49,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE; -import static com.android.server.wm.WindowManagerService.logSurface; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION; import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING; @@ -80,6 +78,7 @@ import android.view.SurfaceControl; import android.view.WindowManager; import com.android.server.EventLogTags; +import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -195,8 +194,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mTopFocusedDisplayId = topFocusedDisplayId; mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId); mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId); - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "New topFocusedDisplayId=" - + topFocusedDisplayId); + ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", + topFocusedDisplayId); } return changed; } @@ -457,13 +456,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void removeReplacedWindows() { - if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION removeReplacedWindows"); mWmService.openSurfaceTransaction(); try { forAllWindows(sRemoveReplacedWindowsConsumer, true /* traverseTopToBottom */); } finally { mWmService.closeSurfaceTransaction("removeReplacedWindows"); - if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION removeReplacedWindows"); } } @@ -539,8 +538,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> Slog.w(TAG_WM, "Looks like we have reclaimed some memory, clearing surface for retry."); if (surfaceController != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin, - "RECOVER DESTROY", false); + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, + "SURFACE RECOVER DESTROY: %s", winAnimator.mWin); winAnimator.destroySurface(); if (winAnimator.mWin.mAppToken != null) { winAnimator.mWin.mAppToken.removeStartingWindow(); @@ -651,8 +650,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> handleResizingWindows(); - if (DEBUG_ORIENTATION && mWmService.mDisplayFrozen) Slog.v(TAG, - "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete); + if (mWmService.mDisplayFrozen) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "With display frozen, orientationChangeComplete=%b", + mOrientationChangeComplete); + } if (mOrientationChangeComplete) { if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) { mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE; @@ -714,7 +716,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } if (mUpdateRotation) { - if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); + ProtoLog.d(WM_DEBUG_ORIENTATION, "Performing post-rotate rotation"); mUpdateRotation = updateRotationUnchecked(); } @@ -868,29 +870,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int privateflags = attrs.privateFlags; boolean displayHasContent = false; - if (DEBUG_KEEP_SCREEN_ON) { - Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked w: " + w - + ", w.mHasSurface: " + w.mHasSurface - + ", w.isOnScreen(): " + onScreen - + ", w.isDisplayedLw(): " + w.isDisplayedLw() - + ", w.mAttrs.userActivityTimeout: " + w.mAttrs.userActivityTimeout); - } + ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, + "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w" + + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", + w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout); if (w.mHasSurface && onScreen) { if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) { mUserActivityTimeout = w.mAttrs.userActivityTimeout; - if (DEBUG_KEEP_SCREEN_ON) { - Slog.d(TAG, "mUserActivityTimeout set to " + mUserActivityTimeout); - } + ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "mUserActivityTimeout set to %d", + mUserActivityTimeout); } } if (w.mHasSurface && canBeSeen) { if ((attrFlags & FLAG_KEEP_SCREEN_ON) != 0) { mHoldScreen = w.mSession; mHoldScreenWindow = w; - } else if (DEBUG_KEEP_SCREEN_ON && w == mWmService.mLastWakeLockHoldingWindow) { - Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked: " + w + " was holding " - + "screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by" - + Debug.getCallers(10)); + } else if (w == mWmService.mLastWakeLockHoldingWindow) { + ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, + "handleNotObscuredLocked: %s was holding screen wakelock but no longer " + + "has FLAG_KEEP_SCREEN_ON!!! called by%s", + w, Debug.getCallers(10)); } if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) { mScreenBrightness = w.mAttrs.screenBrightness; diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index c4bfe4b0c6c5..157bd3b0038b 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -16,10 +16,9 @@ package com.android.server.wm; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING; import static com.android.server.wm.ScreenRotationAnimationProto.STARTED; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; @@ -40,6 +39,8 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; /** @@ -215,10 +216,8 @@ class ScreenRotationAnimation { Slog.w(TAG, "Unable to allocate freeze surface", e); } - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - Slog.i(TAG_WM, - " FREEZE " + mSurfaceControl + ": CREATE"); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, + " FREEZE %s: CREATE", mSurfaceControl); setRotation(t, originalRotation); t.apply(); } @@ -481,11 +480,7 @@ class ScreenRotationAnimation { mSurfaceRotationAnimationController = null; } if (mSurfaceControl != null) { - if (SHOW_TRANSACTIONS || - SHOW_SURFACE_ALLOC) { - Slog.i(TAG_WM, - " FREEZE " + mSurfaceControl + ": DESTROY"); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mSurfaceControl); mSurfaceControl = null; SurfaceControl.Transaction t = mService.mTransactionFactory.get(); if (mRotationLayer != null) { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 72bb355146d1..b047d8f8a7b9 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -24,9 +24,9 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; @@ -56,6 +56,7 @@ import android.view.SurfaceSession; import android.view.WindowManager; import com.android.internal.os.logging.MetricsLoggerWrapper; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; @@ -478,8 +479,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession"); } mSurfaceSession = new SurfaceSession(); - if (SHOW_TRANSACTIONS) Slog.i( - TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession); + ProtoLog.i(WM_SHOW_TRANSACTIONS, " NEW SURFACE SESSION %s", mSurfaceSession); mService.mSessions.add(this); if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { mService.dispatchNewAnimatorScaleLocked(this); @@ -570,7 +570,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Slog.v(TAG_WM, "Last window removed from " + this + ", destroying " + mSurfaceSession); } - if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " KILL SURFACE SESSION " + mSurfaceSession); + ProtoLog.i(WM_SHOW_TRANSACTIONS, " KILL SURFACE SESSION %s", mSurfaceSession); try { mSurfaceSession.kill(); } catch (Exception e) { diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 1c015d0787dd..9712277495df 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -398,9 +398,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return; } - final Rect bounds = display.getBounds(); - final int defaultWidth = bounds.width(); - final int defaultHeight = bounds.height(); + // Use stable frame instead of raw frame to avoid launching freeform windows on top of + // stable insets, which usually are system widgets such as sysbar & navbar. + final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable; + final int defaultWidth = displayStableBounds.width(); + final int defaultHeight = displayStableBounds.height(); int width; int height; @@ -451,6 +453,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } outBounds.set(0, 0, width, height); + outBounds.offset(displayStableBounds.left, displayStableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width)); final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height)); outBounds.offset(xOffset, yOffset); @@ -627,10 +630,14 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) { // Default size, which is letterboxing/pillarboxing in display. That's to say the large // dimension of default size is the small dimension of display size, and the small dimension - // of default size is calculated to keep the same aspect ratio as the display's. - Rect displayBounds = display.getBounds(); - final int portraitHeight = Math.min(displayBounds.width(), displayBounds.height()); - final int otherDimension = Math.max(displayBounds.width(), displayBounds.height()); + // of default size is calculated to keep the same aspect ratio as the display's. Here we use + // stable bounds of displays because that indicates the area that isn't occupied by system + // widgets (e.g. sysbar and navbar). + Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable; + final int portraitHeight = + Math.min(displayStableBounds.width(), displayStableBounds.height()); + final int otherDimension = + Math.max(displayStableBounds.width(), displayStableBounds.height()); final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension; final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight : portraitWidth; @@ -656,16 +663,17 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight)); bounds.set(0, 0, width, height); + bounds.offset(displayStableBounds.left, displayStableBounds.top); } /** * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds - * centers at its center or display's center if inOutBounds is empty. + * centers at its center or display's app bounds center if inOutBounds is empty. */ private void centerBounds(@NonNull ActivityDisplay display, int width, int height, @NonNull Rect inOutBounds) { if (inOutBounds.isEmpty()) { - display.getBounds(inOutBounds); + inOutBounds.set(display.mDisplayContent.mDisplayFrames.mStable); } final int left = inOutBounds.centerX() - width / 2; final int top = inOutBounds.centerY() - height / 2; @@ -674,40 +682,40 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display, @NonNull Rect inOutBounds) { - final Rect displayBounds = display.getBounds(); + final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable; - if (displayBounds.width() < inOutBounds.width() - || displayBounds.height() < inOutBounds.height()) { + if (displayStableBounds.width() < inOutBounds.width() + || displayStableBounds.height() < inOutBounds.height()) { // There is no way for us to fit the bounds in the display without changing width // or height. Just move the start to align with the display. final int layoutDirection = mSupervisor.mRootActivityContainer.getConfiguration().getLayoutDirection(); final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL - ? displayBounds.width() - inOutBounds.width() - : 0; - inOutBounds.offsetTo(left, 0 /* newTop */); + ? displayStableBounds.right - inOutBounds.right + inOutBounds.left + : displayStableBounds.left; + inOutBounds.offsetTo(left, displayStableBounds.top); return; } final int dx; - if (inOutBounds.right > displayBounds.right) { + if (inOutBounds.right > displayStableBounds.right) { // Right edge is out of display. - dx = displayBounds.right - inOutBounds.right; - } else if (inOutBounds.left < displayBounds.left) { + dx = displayStableBounds.right - inOutBounds.right; + } else if (inOutBounds.left < displayStableBounds.left) { // Left edge is out of display. - dx = displayBounds.left - inOutBounds.left; + dx = displayStableBounds.left - inOutBounds.left; } else { // Vertical edges are all in display. dx = 0; } final int dy; - if (inOutBounds.top < displayBounds.top) { + if (inOutBounds.top < displayStableBounds.top) { // Top edge is out of display. - dy = displayBounds.top - inOutBounds.top; - } else if (inOutBounds.bottom > displayBounds.bottom) { + dy = displayStableBounds.top - inOutBounds.top; + } else if (inOutBounds.bottom > displayStableBounds.bottom) { // Bottom edge is out of display. - dy = displayBounds.bottom - inOutBounds.bottom; + dy = displayStableBounds.bottom - inOutBounds.bottom; } else { // Horizontal edges are all in display. dy = 0; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index fc8a27d64fce..b680fa45f00f 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -21,7 +21,7 @@ import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -54,6 +54,7 @@ import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.protolog.common.ProtoLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -297,9 +298,7 @@ class TaskPositioner implements IBinder.DeathRecipient { mDragWindowHandle.frameBottom = p.y; // Pause rotations before a drag. - if (DEBUG_ORIENTATION) { - Slog.d(TAG, "Pausing rotation during re-position"); - } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position"); mDisplayContent.getDisplayRotation().pause(); // Notify InputMonitor to take mDragWindowHandle. @@ -340,9 +339,7 @@ class TaskPositioner implements IBinder.DeathRecipient { mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); // Resume rotations after a drag. - if (DEBUG_ORIENTATION) { - Slog.d(TAG, "Resuming rotation after re-position"); - } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after re-position"); mDisplayContent.getDisplayRotation().resume(); mDisplayContent = null; mClientCallback.unlinkToDeath(this, 0 /* flags */); diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java index f291573f854a..adecc36671c9 100644 --- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java +++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java @@ -15,14 +15,15 @@ */ package com.android.server.wm; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import android.graphics.GraphicBuffer; -import android.util.Slog; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; +import com.android.server.protolog.common.ProtoLog; + import java.util.function.Function; /** @@ -45,10 +46,9 @@ class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable { mTask = task; mWidth = (buffer != null) ? buffer.getWidth() : 1; mHeight = (buffer != null) ? buffer.getHeight() : 1; - if (DEBUG_RECENTS_ANIMATIONS) { - Slog.d(TAG, "Creating TaskScreenshotAnimatable: task: " + task - + "width: " + mWidth + "height: " + mHeight); - } + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", + task, mWidth, mHeight); mSurfaceControl = surfaceControlFactory.apply(new SurfaceSession()) .setName("RecentTaskScreenshotSurface") .setBufferSize(mWidth, mHeight) diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 7456f0d78137..d070850a895f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -42,7 +42,7 @@ import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIB import static com.android.internal.policy.DecorView.getColorViewLeftInset; import static com.android.internal.policy.DecorView.getColorViewTopInset; import static com.android.internal.policy.DecorView.getNavigationBarRect; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -79,6 +79,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; import com.android.internal.view.BaseIWindow; import com.android.server.policy.WindowManagerPolicy.StartingSurface; +import com.android.server.protolog.common.ProtoLog; /** * This class represents a starting window that shows a snapshot. @@ -259,14 +260,14 @@ class TaskSnapshotSurface implements StartingSurface { final long now = SystemClock.uptimeMillis(); if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) { mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); - if (DEBUG_STARTING_WINDOW) { - Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms"); - } + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, + "Defer removing snapshot surface in %dms", (now - mShownTime)); + return; } } try { - if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface"); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing snapshot surface"); mSession.remove(mWindow); } catch (RemoteException e) { // Local call. @@ -286,8 +287,8 @@ class TaskSnapshotSurface implements StartingSurface { private void drawSnapshot() { mSurface.copyFrom(mSurfaceControl); - if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch=" - + mSizeMismatch); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Drawing snapshot surface sizeMismatch=%b", + mSizeMismatch); if (mSizeMismatch) { // The dimensions of the buffer and the window don't match, so attaching the buffer // will fail. Better create a child window with the exact dimensions and fill the parent diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java index 895350b43eeb..513008d3c3c3 100644 --- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java @@ -16,17 +16,17 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapterProto.REMOTE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS; import android.graphics.Point; import android.os.SystemClock; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.function.Consumer; @@ -68,15 +68,11 @@ class WallpaperAnimationAdapter implements AnimationAdapter { final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); service.mRoot.forAllWallpaperWindows(wallpaperWindow -> { if (!wallpaperWindow.getDisplayContent().mWallpaperController.isWallpaperVisible()) { - if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) { - Slog.d(TAG, "\tNot visible=" + wallpaperWindow); - } + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tNot visible=%s", wallpaperWindow); return; } - if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) { - Slog.d(TAG, "\tvisible=" + wallpaperWindow); - } + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tvisible=%s", wallpaperWindow); final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter( wallpaperWindow, durationHint, statusBarTransitionDelay, animationCanceledRunnable); @@ -129,7 +125,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); // Restore z-layering until client has a chance to modify it. t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex()); @@ -139,7 +135,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter { @Override public void onAnimationCancelled(SurfaceControl animationLeash) { - if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationCancelled"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled"); mAnimationCanceledRunnable.accept(this); } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 13902eedbfba..e7b09db9368a 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -24,7 +24,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; @@ -607,8 +606,9 @@ class WallpaperController { boolean processWallpaperDrawPendingTimeout() { if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) { mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT; - if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, - "*** WALLPAPER DRAW TIMEOUT"); + if (DEBUG_WALLPAPER) { + Slog.v(TAG, "*** WALLPAPER DRAW TIMEOUT"); + } // If there was a pending recents animation, start the animation anyways (it's better // to not see the wallpaper than for the animation to not start) @@ -641,9 +641,11 @@ class WallpaperController { WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION); } - if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, - "Wallpaper should be visible but has not been drawn yet. " + - "mWallpaperDrawState=" + mWallpaperDrawState); + if (DEBUG_WALLPAPER) { + Slog.v(TAG, + "Wallpaper should be visible but has not been drawn yet. " + + "mWallpaperDrawState=" + mWallpaperDrawState); + } break; } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 1e206f6be3cc..f437b284637b 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -16,8 +16,8 @@ package com.android.server.wm; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; @@ -32,6 +32,7 @@ import android.view.SurfaceControl; import com.android.server.AnimationThread; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -138,7 +139,7 @@ public class WindowAnimator { Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); } - if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate"); mService.openSurfaceTransaction(); try { final AccessibilityController accessibilityController = @@ -177,7 +178,7 @@ public class WindowAnimator { Slog.wtf(TAG, "Unhandled exception in Window Manager", e); } finally { mService.closeSurfaceTransaction("WindowAnimator"); - if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate"); } boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this); diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index c366e4d6108b..93b0fd9b1fe3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -33,32 +33,19 @@ public class WindowManagerDebugConfig { // Default log tag for the window manager package. static final String TAG_WM = "WindowManager"; - static final boolean DEBUG_RESIZE = false; static final boolean DEBUG = false; - static final boolean DEBUG_ADD_REMOVE = false; - static final boolean DEBUG_FOCUS = false; - static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false; static final boolean DEBUG_ANIM = false; - static final boolean DEBUG_KEYGUARD = false; static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_LAYERS = false; static final boolean DEBUG_INPUT = false; static final boolean DEBUG_INPUT_METHOD = false; static final boolean DEBUG_VISIBILITY = false; - static final boolean DEBUG_WINDOW_MOVEMENT = false; - static final boolean DEBUG_TOKEN_MOVEMENT = false; - static final boolean DEBUG_ORIENTATION = false; - static final boolean DEBUG_APP_ORIENTATION = false; static final boolean DEBUG_CONFIGURATION = false; - static final boolean DEBUG_APP_TRANSITIONS = false; static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false; - static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; static final boolean DEBUG_DRAG = false; - static final boolean DEBUG_SCREEN_ON = false; static final boolean DEBUG_SCREENSHOT = false; - static final boolean DEBUG_BOOT = false; static final boolean DEBUG_LAYOUT_REPEATS = false; static final boolean DEBUG_WINDOW_TRACE = false; static final boolean DEBUG_TASK_MOVEMENT = false; @@ -66,17 +53,9 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_STACK = false; static final boolean DEBUG_DISPLAY = false; static final boolean DEBUG_POWER = false; - static final boolean DEBUG_DIM_LAYER = false; - static final boolean SHOW_SURFACE_ALLOC = false; - static final boolean SHOW_TRANSACTIONS = false; - static final boolean SHOW_VERBOSE_TRANSACTIONS = false && SHOW_TRANSACTIONS; - static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; + static final boolean SHOW_VERBOSE_TRANSACTIONS = false; + static final boolean SHOW_LIGHT_TRANSACTIONS = false; static final boolean SHOW_STACK_CRAWLS = false; static final boolean DEBUG_WINDOW_CROP = false; static final boolean DEBUG_UNKNOWN_APP_VISIBILITY = false; - static final boolean DEBUG_RECENTS_ANIMATIONS = false; - static final boolean DEBUG_REMOTE_ANIMATIONS = DEBUG_APP_TRANSITIONS || false; - - static final String TAG_KEEP_SCREEN_ON = "DebugKeepScreenOn"; - static final boolean DEBUG_KEEP_SCREEN_ON = false; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 169e4159346f..1f45cfb2f53d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.ACCESS_SURFACE_FLINGER; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_APP_TOKENS; @@ -81,27 +82,27 @@ import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.ProtoLogGroup.WM_ERROR; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerServiceDumpProto.DISPLAY_FROZEN; @@ -267,6 +268,7 @@ import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; 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 java.io.BufferedWriter; @@ -973,6 +975,7 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } + /** Listener to notify activity manager about app transitions. */ final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier = new WindowManagerInternal.AppTransitionListener() { @@ -989,7 +992,13 @@ public class WindowManagerService extends IWindowManager.Stub if (atoken == null) { return; } - if (atoken.mLaunchTaskBehind) { + + // While running a recents animation, this will get called early because we show the + // recents animation target activity immediately when the animation starts. Defer the + // mLaunchTaskBehind updates until recents animation finishes. + final boolean isRecentsAnimationTarget = getRecentsAnimationController() != null + && getRecentsAnimationController().isTargetApp(atoken); + if (atoken.mLaunchTaskBehind && !isRecentsAnimationTarget) { try { mActivityTaskManager.notifyLaunchTaskBehindComplete(atoken.token); } catch (RemoteException e) { @@ -997,20 +1006,13 @@ public class WindowManagerService extends IWindowManager.Stub atoken.mLaunchTaskBehind = false; } else { atoken.updateReportedVisibilityLocked(); - if (atoken.mEnteringAnimation) { - if (getRecentsAnimationController() != null - && getRecentsAnimationController().isTargetApp(atoken)) { - // Currently running a recents animation, this will get called early because - // we show the recents animation target activity immediately when the - // animation starts. In this case, we should defer sending the finished - // callback until the animation successfully finishes - return; - } else { - atoken.mEnteringAnimation = false; - try { - mActivityTaskManager.notifyEnterAnimationComplete(atoken.token); - } catch (RemoteException e) { - } + // We should also defer sending the finished callback until the recents animation + // successfully finishes. + if (atoken.mEnteringAnimation && !isRecentsAnimationTarget) { + atoken.mEnteringAnimation = false; + try { + mActivityTaskManager.notifyEnterAnimationComplete(atoken.token); + } catch (RemoteException e) { } } } @@ -1293,7 +1295,7 @@ public class WindowManagerService extends IWindowManager.Stub // The window manager only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { - Slog.wtf(TAG_WM, "Window Manager Crash", e); + ProtoLog.wtf(WM_ERROR, "Window Manager Crash %s", e); } throw e; } @@ -1333,38 +1335,41 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: " - + displayId + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does " + + "not exist: %d. Aborting.", displayId); return WindowManagerGlobal.ADD_INVALID_DISPLAY; } if (!displayContent.hasAccess(session.mUid)) { - Slog.w(TAG_WM, "Attempted to add window to a display for which the application " - + "does not have access: " + displayId + ". Aborting."); + ProtoLog.w(WM_ERROR, + "Attempted to add window to a display for which the application " + + "does not have access: %d. Aborting.", displayId); return WindowManagerGlobal.ADD_INVALID_DISPLAY; } if (mWindowMap.containsKey(client.asBinder())) { - Slog.w(TAG_WM, "Window " + client + " is already added"); + ProtoLog.w(WM_ERROR, "Window %s is already added", client); return WindowManagerGlobal.ADD_DUPLICATE_ADD; } if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { parentWindow = windowForClientLocked(null, attrs.token, false); if (parentWindow == null) { - Slog.w(TAG_WM, "Attempted to add window with token that is not a window: " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) { - Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } } if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) { - Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display. Aborting."); + ProtoLog.w(WM_ERROR, + "Attempted to add private presentation window to a non-private display. " + + "Aborting."); return WindowManagerGlobal.ADD_PERMISSION_DENIED; } @@ -1382,46 +1387,48 @@ public class WindowManagerService extends IWindowManager.Stub if (token == null) { if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { - Slog.w(TAG_WM, "Attempted to add application window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add application window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_INPUT_METHOD) { - Slog.w(TAG_WM, "Attempted to add input method window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add input method window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_VOICE_INTERACTION) { - Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, + "Attempted to add voice interaction window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_WALLPAPER) { - Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_DREAM) { - Slog.w(TAG_WM, "Attempted to add Dream window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add Dream window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_QS_DIALOG) { - Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (rootType == TYPE_ACCESSIBILITY_OVERLAY) { - Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, + "Attempted to add Accessibility overlay window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } if (type == TYPE_TOAST) { // Apps targeting SDK above N MR1 cannot arbitrary add toast windows. if (doesAddToastWindowRequireToken(attrs.packageName, callingUid, parentWindow)) { - Slog.w(TAG_WM, "Attempted to add a toast window with unknown token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add a toast window with unknown token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } @@ -1430,49 +1437,52 @@ public class WindowManagerService extends IWindowManager.Stub (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; token = new WindowToken(this, binder, type, false, displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); - } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { + } else if (rootType >= FIRST_APPLICATION_WINDOW + && rootType <= LAST_APPLICATION_WINDOW) { atoken = token.asAppWindowToken(); if (atoken == null) { - Slog.w(TAG_WM, "Attempted to add window with non-application token " - + token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add window with non-application token " + + ".%s Aborting.", token); return WindowManagerGlobal.ADD_NOT_APP_TOKEN; } else if (atoken.removed) { - Slog.w(TAG_WM, "Attempted to add window with exiting application token " - + token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token " + + ".%s Aborting.", token); return WindowManagerGlobal.ADD_APP_EXITING; } else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) { - Slog.w(TAG_WM, "Attempted to add starting window to token with already existing" - + " starting window"); + ProtoLog.w(WM_ERROR, + "Attempted to add starting window to token with already existing" + + " starting window"); return WindowManagerGlobal.ADD_DUPLICATE_ADD; } } else if (rootType == TYPE_INPUT_METHOD) { if (token.windowType != TYPE_INPUT_METHOD) { - Slog.w(TAG_WM, "Attempted to add input method window with bad token " - + attrs.token + ". Aborting."); - return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + ProtoLog.w(WM_ERROR, "Attempted to add input method window with bad token " + + "%s. Aborting.", attrs.token); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (rootType == TYPE_VOICE_INTERACTION) { if (token.windowType != TYPE_VOICE_INTERACTION) { - Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token " - + attrs.token + ". Aborting."); - return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + ProtoLog.w(WM_ERROR, "Attempted to add voice interaction window with bad token " + + "%s. Aborting.", attrs.token); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (rootType == TYPE_WALLPAPER) { if (token.windowType != TYPE_WALLPAPER) { - Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token " - + attrs.token + ". Aborting."); - return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with bad token " + + "%s. Aborting.", attrs.token); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (rootType == TYPE_DREAM) { if (token.windowType != TYPE_DREAM) { - Slog.w(TAG_WM, "Attempted to add Dream window with bad token " - + attrs.token + ". Aborting."); - return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + ProtoLog.w(WM_ERROR, "Attempted to add Dream window with bad token " + + "%s. Aborting.", attrs.token); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) { if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) { - Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, + "Attempted to add Accessibility overlay window with bad token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (type == TYPE_TOAST) { @@ -1480,18 +1490,19 @@ public class WindowManagerService extends IWindowManager.Stub addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName, callingUid, parentWindow); if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) { - Slog.w(TAG_WM, "Attempted to add a toast window with bad token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add a toast window with bad token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (type == TYPE_QS_DIALOG) { if (token.windowType != TYPE_QS_DIALOG) { - Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token " - + attrs.token + ". Aborting."); + ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with bad token " + + "%s. Aborting.", attrs.token); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } else if (token.asAppWindowToken() != null) { - Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType); + ProtoLog.w(WM_ERROR, "Non-null appWindowToken for system window of rootType=%d", + rootType); // It is not valid to use an app token with other system types; we will // instead make a new token for it (as if null had been passed in for the token). attrs.token = null; @@ -1505,13 +1516,13 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to // continue. - Slog.w(TAG_WM, "Adding window client " + client.asBinder() - + " that is dead, aborting."); + ProtoLog.w(WM_ERROR, "Adding window client %s" + + " that is dead, aborting.", client.asBinder()); return WindowManagerGlobal.ADD_APP_EXITING; } if (win.getDisplayContent() == null) { - Slog.w(TAG_WM, "Adding window to Display that has been removed."); + ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed."); return WindowManagerGlobal.ADD_INVALID_DISPLAY; } @@ -1543,7 +1554,7 @@ public class WindowManagerService extends IWindowManager.Stub // schedule hiding all of its toast windows. if (type == TYPE_TOAST) { if (!displayContent.canAddToastWindowForUid(callingUid)) { - Slog.w(TAG_WM, "Adding more than one toast window for UID at a time."); + ProtoLog.w(WM_ERROR, "Adding more than one toast window for UID at a time."); return WindowManagerGlobal.ADD_DUPLICATE_ADD; } // Make sure this happens before we moved focus as one can make the @@ -1589,8 +1600,8 @@ public class WindowManagerService extends IWindowManager.Stub final AppWindowToken aToken = token.asAppWindowToken(); if (type == TYPE_APPLICATION_STARTING && aToken != null) { aToken.startingWindow = win; - if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken - + " startingWindow=" + win); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", + aToken, win); } boolean imMayMove = true; @@ -1607,7 +1618,7 @@ public class WindowManagerService extends IWindowManager.Stub if (type == TYPE_WALLPAPER) { displayContent.mWallpaperController.clearLastWallpaperTimeoutTime(); displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) { + } else if ((attrs.flags & FLAG_SHOW_WALLPAPER) != 0) { displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) { // If there is currently a wallpaper being shown, and @@ -1692,10 +1703,9 @@ public class WindowManagerService extends IWindowManager.Stub } displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); - if (DEBUG || DEBUG_ADD_REMOVE) { - Slog.v(TAG_WM, "addWindow: New client " + client.asBinder() - + ": window=" + win + " Callers=" + Debug.getCallers(5)); - } + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s" + + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5)); + if (win.isVisibleOrAdding() && displayContent.updateOrientation()) { displayContent.sendNewConfiguration(); @@ -1858,7 +1868,7 @@ public class WindowManagerService extends IWindowManager.Stub * forgetting to add the wiring when a new parent of WindowState is added. */ void postWindowRemoveCleanupLocked(WindowState win) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "postWindowRemoveCleanupLocked: %s", win); mWindowMap.remove(win.mClient.asBinder()); final DisplayContent dc = win.getDisplayContent(); @@ -1873,7 +1883,7 @@ public class WindowManagerService extends IWindowManager.Stub mResizingWindows.remove(win); updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */); mWindowsChanged = true; - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win); + ProtoLog.v(WM_DEBUG_WINDOW_MOVEMENT, "Final remove of window: %s", win); final DisplayContent displayContent = win.getDisplayContent(); if (displayContent.mInputMethodWindow == win) { @@ -1882,7 +1892,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowToken token = win.mToken; final AppWindowToken atoken = win.mAppToken; - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Removing " + win + " from " + token); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Removing %s from %s", win, token); // Window will already be removed from token before this post clean-up method is called. if (token.isEmpty()) { if (!token.mPersistOnEmpty) { @@ -1942,11 +1952,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - static void logSurface(SurfaceControl s, String title, String msg) { - String str = " SURFACE " + s + ": " + msg + " / " + title; - Slog.i(TAG_WM, str); - } - static void logWithStack(String tag, String s) { RuntimeException e = null; if (SHOW_STACK_CRAWLS) { @@ -1961,8 +1966,8 @@ public class WindowManagerService extends IWindowManager.Stub try { synchronized (mGlobalLock) { WindowState w = windowForClientLocked(session, client, false); - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, - "transparentRegionHint=" + region, false); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE transparentRegionHint=%s: %s", + region, w); if ((w != null) && w.mHasSurface) { w.mWinAnimator.setTransparentRegionHintLocked(region); @@ -2186,12 +2191,10 @@ public class WindowManagerService extends IWindowManager.Stub win.mInRelayout = true; win.mViewVisibility = viewVisibility; - if (DEBUG_SCREEN_ON) { - RuntimeException stack = new RuntimeException(); - stack.fillInStackTrace(); - Slog.i(TAG_WM, "Relayout " + win + ": oldVis=" + oldVisibility - + " newVis=" + viewVisibility, stack); - } + ProtoLog.i(WM_DEBUG_SCREEN_ON, + "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility, + viewVisibility, new RuntimeException().fillInStackTrace()); + win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; @@ -2236,9 +2239,9 @@ public class WindowManagerService extends IWindowManager.Stub } catch (Exception e) { displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); - Slog.w(TAG_WM, "Exception thrown when creating surface for client " - + client + " (" + win.mAttrs.getTitle() + ")", - e); + ProtoLog.w(WM_ERROR, + "Exception thrown when creating surface for client %s (%s). %s", + client, win.mAttrs.getTitle(), e); Binder.restoreCallingIdentity(origId); return 0; } @@ -2362,21 +2365,21 @@ public class WindowManagerService extends IWindowManager.Stub outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win)); if (DEBUG) { Slog.v(TAG_WM, "Relayout given client " + client.asBinder() - + ", requestedWidth=" + requestedWidth - + ", requestedHeight=" + requestedHeight - + ", viewVisibility=" + viewVisibility - + "\nRelayout returning frame=" + outFrame - + ", surface=" + outSurfaceControl); + + ", requestedWidth=" + requestedWidth + + ", requestedHeight=" + requestedHeight + + ", viewVisibility=" + viewVisibility + + "\nRelayout returning frame=" + outFrame + + ", surface=" + outSurfaceControl); } - if (DEBUG || DEBUG_FOCUS) { - Slog.v(TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange); - } + ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b", + win, focusMayChange); result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0; if (DEBUG_LAYOUT) { - Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString()); + Slog.v(TAG_WM, + "Relayout complete " + win + ": outFrame=" + outFrame.toShortString()); } win.mInRelayout = false; @@ -2454,11 +2457,12 @@ public class WindowManagerService extends IWindowManager.Stub } if (surfaceController != null) { surfaceController.getSurfaceControl(outSurfaceControl); - if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurfaceControl + ": copied"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl); + } else { // For some reason there isn't a surface. Clear the // caller's object so they see the same state. - Slog.w(TAG_WM, "Failed to create surface control for " + win); + ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win); outSurfaceControl.release(); } @@ -2487,8 +2491,8 @@ public class WindowManagerService extends IWindowManager.Stub try { synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); - if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "finishDrawingWindow: " + win + " mDrawState=" - + (win != null ? win.mWinAnimator.drawStateToString() : "null")); + ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s", + win, (win != null ? win.mWinAnimator.drawStateToString() : "null")); if (win != null && win.mWinAnimator.finishDrawingLocked(postDrawTransaction)) { if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { win.getDisplayContent().pendingLayoutChanges |= @@ -2513,9 +2517,8 @@ public class WindowManagerService extends IWindowManager.Stub == PackageManager.PERMISSION_GRANTED) { return true; } - final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() + " requires " + permission; - Slog.w(TAG_WM, msg); + ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s", + func, Binder.getCallingPid(), Binder.getCallingUid(), permission); return false; } @@ -2528,16 +2531,16 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */); if (dc == null) { - Slog.w(TAG_WM, "addWindowToken: Attempted to add token: " + binder - + " for non-exiting displayId=" + displayId); + ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s" + + " for non-exiting displayId=%d", binder, displayId); return; } WindowToken token = dc.getWindowToken(binder); if (token != null) { - Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder - + " for already created window token: " + token - + " displayId=" + displayId); + ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s" + + " for already created window token: %s" + + " displayId=%d", binder, token, displayId); return; } if (type == TYPE_WALLPAPER) { @@ -2560,15 +2563,16 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { - Slog.w(TAG_WM, "removeWindowToken: Attempted to remove token: " + binder - + " for non-exiting displayId=" + displayId); + ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" + + " for non-exiting displayId=%d", binder, displayId); return; } final WindowToken token = dc.removeWindowToken(binder); if (token == null) { - Slog.w(TAG_WM, - "removeWindowToken: Attempted to remove non-existing token: " + binder); + ProtoLog.w(WM_ERROR, + "removeWindowToken: Attempted to remove non-existing token: %s", + binder); return; } @@ -3208,14 +3212,11 @@ public class WindowManagerService extends IWindowManager.Stub public void enableScreenAfterBoot() { synchronized (mGlobalLock) { - if (DEBUG_BOOT) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG_WM, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled - + " mForceDisplayEnabled=" + mForceDisplayEnabled - + " mShowingBootMessages=" + mShowingBootMessages - + " mSystemBooted=" + mSystemBooted, here); - } + ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b " + + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. " + + "%s", + mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, + new RuntimeException("here").fillInStackTrace()); if (mSystemBooted) { return; } @@ -3239,14 +3240,11 @@ public class WindowManagerService extends IWindowManager.Stub } void enableScreenIfNeededLocked() { - if (DEBUG_BOOT) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG_WM, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled - + " mForceDisplayEnabled=" + mForceDisplayEnabled - + " mShowingBootMessages=" + mShowingBootMessages - + " mSystemBooted=" + mSystemBooted, here); - } + ProtoLog.i(WM_DEBUG_BOOT, "enableScreenIfNeededLocked: mDisplayEnabled=%b " + + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. " + + "%s", + mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, + new RuntimeException("here").fillInStackTrace()); if (mDisplayEnabled) { return; } @@ -3261,7 +3259,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDisplayEnabled) { return; } - Slog.w(TAG_WM, "***** BOOT TIMEOUT: forcing display enabled"); + ProtoLog.w(WM_ERROR, "***** BOOT TIMEOUT: forcing display enabled"); mForceDisplayEnabled = true; } performEnableScreen(); @@ -3276,11 +3274,10 @@ public class WindowManagerService extends IWindowManager.Stub private void performEnableScreen() { synchronized (mGlobalLock) { - if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled - + " mForceDisplayEnabled=" + mForceDisplayEnabled - + " mShowingBootMessages=" + mShowingBootMessages - + " mSystemBooted=" + mSystemBooted - + " mOnlyCore=" + mOnlyCore, + ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: mDisplayEnabled=%b" + + " mForceDisplayEnabled=%b" + " mShowingBootMessages=%b" + + " mSystemBooted=%b mOnlyCore=%b. %s", mDisplayEnabled, + mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, mOnlyCore, new RuntimeException("here").fillInStackTrace()); if (mDisplayEnabled) { return; @@ -3294,10 +3291,12 @@ public class WindowManagerService extends IWindowManager.Stub } // Don't enable the screen until all existing windows have been drawn. - if (!mForceDisplayEnabled - // TODO(multidisplay): Expand to all displays? - && getDefaultDisplayContentLocked().checkWaitingForWindows()) { - return; + if (!mForceDisplayEnabled) { + for (int i = mRoot.getChildCount() - 1; i >= 0; i--) { + if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) { + return; + } + } } if (!mBootAnimationStopped) { @@ -3310,14 +3309,14 @@ public class WindowManagerService extends IWindowManager.Stub } if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) { - if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete"); + ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete"); return; } try { IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); if (surfaceFlinger != null) { - Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); + ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); Parcel data = Parcel.obtain(); data.writeInterfaceToken("android.ui.ISurfaceComposer"); surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED @@ -3325,13 +3324,13 @@ public class WindowManagerService extends IWindowManager.Stub data.recycle(); } } catch (RemoteException ex) { - Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!"); + ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!"); } EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis()); Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0); mDisplayEnabled = true; - if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!"); + ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!"); // Enable input dispatch. mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled); @@ -3353,24 +3352,21 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED); mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED, BOOT_ANIMATION_POLL_INTERVAL); - if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Waiting for anim complete"); + ProtoLog.i(WM_DEBUG_BOOT, "checkBootAnimationComplete: Waiting for anim complete"); return false; } - if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Animation complete!"); + ProtoLog.i(WM_DEBUG_BOOT, "checkBootAnimationComplete: Animation complete!"); return true; } public void showBootMessage(final CharSequence msg, final boolean always) { boolean first = false; synchronized (mGlobalLock) { - if (DEBUG_BOOT) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG_WM, "showBootMessage: msg=" + msg + " always=" + always - + " mAllowBootMessages=" + mAllowBootMessages - + " mShowingBootMessages=" + mShowingBootMessages - + " mSystemBooted=" + mSystemBooted, here); - } + ProtoLog.i(WM_DEBUG_BOOT, "showBootMessage: msg=%s always=%b" + + " mAllowBootMessages=%b mShowingBootMessages=%b" + + " mSystemBooted=%b. %s", msg, always, mAllowBootMessages, + mShowingBootMessages, mSystemBooted, + new RuntimeException("here").fillInStackTrace()); if (!mAllowBootMessages) { return; } @@ -3392,14 +3388,11 @@ public class WindowManagerService extends IWindowManager.Stub } public void hideBootMessagesLocked() { - if (DEBUG_BOOT) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG_WM, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled - + " mForceDisplayEnabled=" + mForceDisplayEnabled - + " mShowingBootMessages=" + mShowingBootMessages - + " mSystemBooted=" + mSystemBooted, here); - } + ProtoLog.i(WM_DEBUG_BOOT, "hideBootMessagesLocked: mDisplayEnabled=%b" + + " mForceDisplayEnabled=%b mShowingBootMessages=%b" + + " mSystemBooted=%b. %s", mDisplayEnabled, mForceDisplayEnabled, + mShowingBootMessages, mSystemBooted, + new RuntimeException("here").fillInStackTrace()); if (mShowingBootMessages) { mShowingBootMessages = false; mPolicy.hideBootMessages(); @@ -3691,8 +3684,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires SET_ORIENTATION permission"); } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "thawRotation: mRotation=" - + getDefaultDisplayRotation()); + ProtoLog.v(WM_DEBUG_ORIENTATION, "thawRotation: mRotation=%d", getDefaultDisplayRotation()); long origId = Binder.clearCallingIdentity(); try { @@ -3741,9 +3733,9 @@ public class WindowManagerService extends IWindowManager.Stub } private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { - if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:" - + " alwaysSendConfiguration=" + alwaysSendConfiguration - + " forceRelayout=" + forceRelayout); + ProtoLog.v(WM_DEBUG_ORIENTATION, "updateRotationUnchecked:" + + " alwaysSendConfiguration=%b forceRelayout=%b", + alwaysSendConfiguration, forceRelayout); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation"); @@ -3992,7 +3984,7 @@ public class WindowManagerService extends IWindowManager.Stub try { return mViewServer.start(); } catch (IOException e) { - Slog.w(TAG_WM, "View server did not start"); + ProtoLog.w(WM_ERROR, "View server did not start"); } } return false; @@ -4002,7 +3994,7 @@ public class WindowManagerService extends IWindowManager.Stub mViewServer = new ViewServer(this, port); return mViewServer.start(); } catch (IOException e) { - Slog.w(TAG_WM, "View server did not start"); + ProtoLog.w(WM_ERROR, "View server did not start"); } return false; } @@ -4232,7 +4224,8 @@ public class WindowManagerService extends IWindowManager.Stub } } catch (Exception e) { - Slog.w(TAG_WM, "Could not send command " + command + " with parameters " + parameters, e); + ProtoLog.w(WM_ERROR, "Could not send command %s with parameters %s. %s", command, + parameters, e); success = false; } finally { if (data != null) { @@ -4381,9 +4374,9 @@ public class WindowManagerService extends IWindowManager.Stub public boolean detectSafeMode() { if (!mInputManagerCallback.waitForInputDevicesReady( INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) { - Slog.w(TAG_WM, "Devices still not ready after waiting " - + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS - + " milliseconds before attempting to detect safe mode."); + ProtoLog.w(WM_ERROR, "Devices still not ready after waiting %d" + + " milliseconds before attempting to detect safe mode.", + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS); } if (Settings.Global.getInt( @@ -4411,14 +4404,14 @@ public class WindowManagerService extends IWindowManager.Stub } catch (IllegalArgumentException e) { } if (mSafeMode) { - Log.i(TAG_WM, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState - + " dpad=" + dpadState + " trackball=" + trackballState + ")"); + ProtoLog.i(WM_ERROR, "SAFE MODE ENABLED (menu=%d s=%d dpad=%d" + + " trackball=%d)", menuState, sState, dpadState, trackballState); // May already be set if (for instance) this process has crashed if (SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) == 0) { SystemProperties.set(ShutdownThread.RO_SAFEMODE_PROPERTY, "1"); } } else { - Log.i(TAG_WM, "SAFE MODE not enabled"); + ProtoLog.i(WM_ERROR, "SAFE MODE not enabled"); } mPolicy.setSafeMode(mSafeMode); return mSafeMode; @@ -4577,10 +4570,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } displayContent.mLastFocus = newFocus; - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Focus moving from " + lastFocus + - " to " + newFocus + " displayId=" + displayContent.getDisplayId()); + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus moving from %s" + + " to %s displayId=%d", lastFocus, newFocus, + displayContent.getDisplayId()); if (newFocus != null && lastFocus != null && !newFocus.isDisplayedLw()) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Delaying loss of focus..."); + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Delaying loss of focus..."); displayContent.mLosingFocus.add(lastFocus); lastFocus = null; } @@ -4594,13 +4588,13 @@ public class WindowManagerService extends IWindowManager.Stub } if (newFocus != null) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus); + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Gaining focus: %s", newFocus); newFocus.reportFocusChangedSerialized(true, mInTouchMode); notifyFocusChanged(); } if (lastFocus != null) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus); + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing focus: %s", lastFocus); lastFocus.reportFocusChangedSerialized(false, mInTouchMode); } break; @@ -4617,7 +4611,7 @@ public class WindowManagerService extends IWindowManager.Stub final int N = losers.size(); for (int i = 0; i < N; i++) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing delayed focus: " + + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing delayed focus: %s", losers.get(i)); losers.get(i).reportFocusChangedSerialized(false, mInTouchMode); } @@ -4700,9 +4694,9 @@ public class WindowManagerService extends IWindowManager.Stub case APP_FREEZE_TIMEOUT: { synchronized (mGlobalLock) { - Slog.w(TAG_WM, "App freeze timeout expired."); + ProtoLog.w(WM_ERROR, "App freeze timeout expired."); mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT; - for (int i = mAppFreezeListeners.size() - 1; i >=0 ; --i) { + for (int i = mAppFreezeListeners.size() - 1; i >= 0; --i) { mAppFreezeListeners.get(i).onAppFreezeTimeout(); } } @@ -4743,7 +4737,8 @@ public class WindowManagerService extends IWindowManager.Stub case WAITING_FOR_DRAWN_TIMEOUT: { Runnable callback = null; synchronized (mGlobalLock) { - Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn); + ProtoLog.w(WM_ERROR, "Timeout waiting for drawn: undrawn=%s", + mWaitingForDrawn); mWaitingForDrawn.clear(); callback = mWaitingForDrawnCallback; mWaitingForDrawnCallback = null; @@ -4817,7 +4812,7 @@ public class WindowManagerService extends IWindowManager.Stub case CHECK_IF_BOOT_ANIMATION_FINISHED: { final boolean bootAnimationComplete; synchronized (mGlobalLock) { - if (DEBUG_BOOT) Slog.i(TAG_WM, "CHECK_IF_BOOT_ANIMATION_FINISHED:"); + ProtoLog.i(WM_DEBUG_BOOT, "CHECK_IF_BOOT_ANIMATION_FINISHED:"); bootAnimationComplete = checkBootAnimationCompleteLocked(); } if (bootAnimationComplete) { @@ -5031,10 +5026,10 @@ public class WindowManagerService extends IWindowManager.Stub int width, height; try { width = Integer.parseInt(sizeStr.substring(0, pos)); - height = Integer.parseInt(sizeStr.substring(pos+1)); + height = Integer.parseInt(sizeStr.substring(pos + 1)); if (displayContent.mBaseDisplayWidth != width || displayContent.mBaseDisplayHeight != height) { - Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height); + ProtoLog.i(WM_ERROR, "FORCED DISPLAY SIZE: %dx%d", width, height); displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity); changed = true; @@ -5055,7 +5050,7 @@ public class WindowManagerService extends IWindowManager.Stub int mode = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DISPLAY_SCALING_FORCE, 0); if (displayContent.mDisplayScalingDisabled != (mode != 0)) { - Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED"); + ProtoLog.i(WM_ERROR, "FORCED DISPLAY SCALING DISABLED"); displayContent.mDisplayScalingDisabled = true; changed = true; } @@ -5235,7 +5230,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException( "Requested window " + client + " does not exist"); } - Slog.w(TAG_WM, "Failed looking up window callers=" + Debug.getCallers(3)); + ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3)); return null; } if (session != null && win.mSession != session) { @@ -5243,7 +5238,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException("Requested window " + client + " is in session " + win.mSession + ", not " + session); } - Slog.w(TAG_WM, "Failed looking up window callers=" + Debug.getCallers(3)); + ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3)); return null; } @@ -5255,7 +5250,7 @@ public class WindowManagerService extends IWindowManager.Stub // it frozen/off until this window draws at its new // orientation. if (!w.mToken.okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w); w.setOrientationChanging(true); w.mLastFreezeDuration = 0; mRoot.mOrientationChangeComplete = false; @@ -5275,22 +5270,22 @@ public class WindowManagerService extends IWindowManager.Stub } for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) { WindowState win = mWaitingForDrawn.get(j); - if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win + - ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() + - " mHasSurface=" + win.mHasSurface + - " drawState=" + win.mWinAnimator.mDrawState); + ProtoLog.i(WM_DEBUG_SCREEN_ON, + "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", + win, win.mRemoved, win.isVisibleLw(), win.mHasSurface, + win.mWinAnimator.mDrawState); if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) { // Window has been removed or hidden; no draw will now happen, so stop waiting. - if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win); + ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win); mWaitingForDrawn.remove(win); } else if (win.hasDrawnLw()) { // Window is now drawn (and shown). - if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win); + ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win); mWaitingForDrawn.remove(win); } } if (mWaitingForDrawn.isEmpty()) { - if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!"); + ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!"); mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT); mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN); } @@ -5307,19 +5302,15 @@ public class WindowManagerService extends IWindowManager.Stub final boolean state = mHoldingScreenWakeLock.isHeld(); if (hold != state) { if (hold) { - if (DEBUG_KEEP_SCREEN_ON) { - Slog.d(TAG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to " - + mRoot.mHoldScreenWindow); - } + ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to %s", + mRoot.mHoldScreenWindow); mLastWakeLockHoldingWindow = mRoot.mHoldScreenWindow; mLastWakeLockObscuringWindow = null; mHoldingScreenWakeLock.acquire(); mPolicy.keepScreenOnStartedLw(); } else { - if (DEBUG_KEEP_SCREEN_ON) { - Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by " - + mRoot.mObscuringWindow); - } + ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by %s", + mRoot.mObscuringWindow); mLastWakeLockHoldingWindow = null; mLastWakeLockObscuringWindow = mRoot.mObscuringWindow; mPolicy.keepScreenOnStoppedLw(); @@ -5363,10 +5354,9 @@ public class WindowManagerService extends IWindowManager.Stub return; } - if (DEBUG_ORIENTATION) Slog.d(TAG_WM, - "startFreezingDisplayLocked: exitAnim=" - + exitAnim + " enterAnim=" + enterAnim - + " called by " + Debug.getCallers(8)); + ProtoLog.d(WM_DEBUG_ORIENTATION, + "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", + exitAnim, enterAnim, Debug.getCallers(8)); mScreenFrozenLock.acquire(); mDisplayFrozen = true; @@ -5418,17 +5408,17 @@ public class WindowManagerService extends IWindowManager.Stub if (waitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE || mClientFreezingScreen || numOpeningApps > 0) { - if (DEBUG_ORIENTATION) Slog.d(TAG_WM, - "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + waitingForConfig - + ", mAppsFreezingScreen=" + mAppsFreezingScreen - + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen - + ", mClientFreezingScreen=" + mClientFreezingScreen - + ", mOpeningApps.size()=" + numOpeningApps); + ProtoLog.d(WM_DEBUG_ORIENTATION, + "stopFreezingDisplayLocked: Returning mWaitingForConfig=%b, " + + "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, " + + "mClientFreezingScreen=%b, mOpeningApps.size()=%d", + waitingForConfig, mAppsFreezingScreen, mWindowsFreezingScreen, + mClientFreezingScreen, numOpeningApps); return; } - if (DEBUG_ORIENTATION) Slog.d(TAG_WM, - "stopFreezingDisplayLocked: Unfreezing now"); + ProtoLog.d(WM_DEBUG_ORIENTATION, + "stopFreezingDisplayLocked: Unfreezing now"); // We must make a local copy of the displayId as it can be potentially overwritten later on @@ -5446,7 +5436,7 @@ public class WindowManagerService extends IWindowManager.Stub sb.append(" due to "); sb.append(mLastFinishedFreezeSource); } - Slog.i(TAG_WM, sb.toString()); + ProtoLog.i(WM_ERROR, "%s", sb.toString()); mH.removeMessages(H.APP_FREEZE_TIMEOUT); mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT); if (PROFILE_ORIENTATION) { @@ -5458,7 +5448,7 @@ public class WindowManagerService extends IWindowManager.Stub ScreenRotationAnimation screenRotationAnimation = displayContent == null ? null : displayContent.getRotationAnimation(); if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) { - if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation"); + ProtoLog.i(WM_DEBUG_ORIENTATION, "**** Dismissing screen rotation animation"); DisplayInfo displayInfo = displayContent.getDisplayInfo(); // Get rotation animation again, with new top window if (!displayContent.getDisplayRotation().validateRotationAnimation( @@ -5501,7 +5491,7 @@ public class WindowManagerService extends IWindowManager.Stub mScreenFrozenLock.release(); if (updateRotation && displayContent != null) { - if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation"); + ProtoLog.d(WM_DEBUG_ORIENTATION, "Performing post-rotate rotation"); configChanged |= displayContent.updateRotationUnchecked(); } @@ -6314,17 +6304,20 @@ public class WindowManagerService extends IWindowManager.Stub /** * Hint to a token that its activity will relaunch, which will trigger removal and addition of * a window. + * * @param token Application token for which the activity will be relaunched. */ void setWillReplaceWindow(IBinder token, boolean animate) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { - Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token); + ProtoLog.w(WM_ERROR, "Attempted to set replacing window on non-existing app token %s", + token); return; } if (!appWindowToken.hasContentToDisplay()) { - Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content" - + token); + ProtoLog.w(WM_ERROR, + "Attempted to set replacing window on app token with no content %s", + token); return; } appWindowToken.setWillReplaceWindows(animate); @@ -6346,13 +6339,15 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { - Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " - + token); + ProtoLog.w(WM_ERROR, + "Attempted to set replacing window on non-existing app token %s", + token); return; } if (!appWindowToken.hasContentToDisplay()) { - Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content" - + token); + ProtoLog.w(WM_ERROR, + "Attempted to set replacing window on app token with no content %s", + token); return; } @@ -6372,14 +6367,14 @@ public class WindowManagerService extends IWindowManager.Stub * * If we're not replacing the window, clear the replace window settings of the app. * - * @param token Application token for the activity whose window might be replaced. + * @param token Application token for the activity whose window might be replaced. * @param replacing Whether the window is being replaced or not. */ void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { - Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " - + token); + ProtoLog.w(WM_ERROR, "Attempted to reset replacing window on non-existing app token %s", + token); return; } if (replacing) { @@ -6568,7 +6563,7 @@ public class WindowManagerService extends IWindowManager.Stub } WindowState callingWin = windowForClientLocked(null, client, false); if (callingWin == null) { - Slog.w(TAG_WM, "Bad requesting window " + client); + ProtoLog.w(WM_ERROR, "Bad requesting window %s", client); return; } final DisplayContent displayContent = callingWin.getDisplayContent(); @@ -6585,7 +6580,7 @@ public class WindowManagerService extends IWindowManager.Stub windowUnderPointer.translateToWindowX(mouseX), windowUnderPointer.translateToWindowY(mouseY)); } catch (RemoteException e) { - Slog.w(TAG_WM, "unable to update pointer icon"); + ProtoLog.w(WM_ERROR, "unable to update pointer icon"); } } } @@ -6602,7 +6597,7 @@ public class WindowManagerService extends IWindowManager.Stub windowUnderPointer.translateToWindowX(latestX), windowUnderPointer.translateToWindowY(latestY)); } catch (RemoteException e) { - Slog.w(TAG_WM, "unable to restore pointer icon"); + ProtoLog.w(WM_ERROR, "unable to restore pointer icon"); } } else { InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_DEFAULT); @@ -6632,7 +6627,7 @@ public class WindowManagerService extends IWindowManager.Stub try { final WindowState win = windowForClientLocked(null, client, false); if (win == null) { - Slog.w(TAG_WM, "Bad requesting window " + client); + ProtoLog.w(WM_ERROR, "Bad requesting window %s", client); return; } getDisplayContentOrCreate(displayId, null).reparentDisplayContent(win, sc); @@ -6657,7 +6652,7 @@ public class WindowManagerService extends IWindowManager.Stub try { final WindowState win = windowForClientLocked(null, client, false); if (win == null) { - Slog.w(TAG_WM, "Bad requesting window " + client); + ProtoLog.w(WM_ERROR, "Bad requesting window %s", client); return; } final DisplayContent displayContent = mRoot.getDisplayContent(displayId); @@ -6684,7 +6679,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final WindowState callingWin = windowForClientLocked(null, client, false); if (callingWin == null) { - Slog.w(TAG_WM, "Bad requesting window " + client); + ProtoLog.w(WM_ERROR, "Bad requesting window %s", client); return; } callingWin.updateTapExcludeRegion(regionId, region); @@ -6723,8 +6718,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to get windowing mode of a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to get windowing mode of a display that does not exist: %d", + displayId); return WindowConfiguration.WINDOWING_MODE_UNDEFINED; } return mDisplayWindowSettings.getWindowingModeLocked(displayContent); @@ -6740,8 +6736,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to set windowing mode to a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to set windowing mode to a display that does not exist: %d", + displayId); return; } @@ -6776,8 +6773,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to get remove mode of a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to get remove mode of a display that does not exist: %d", + displayId); return REMOVE_CONTENT_MODE_UNDEFINED; } return mDisplayWindowSettings.getRemoveContentModeLocked(displayContent); @@ -6793,8 +6791,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to set remove mode to a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to set remove mode to a display that does not exist: %d", + displayId); return; } @@ -6813,8 +6812,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to get flag of a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, "Attempted to get flag of a display that does not exist: %d", + displayId); return false; } return mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(displayContent); @@ -6831,8 +6830,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to set flag to a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: %d", + displayId); return; } @@ -6852,8 +6851,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to get system decors flag of a display that does " - + "not exist: " + displayId); + ProtoLog.w(WM_ERROR, "Attempted to get system decors flag of a display that does " + + "not exist: %d", displayId); return false; } if (displayContent.isUntrustedVirtualDisplay()) { @@ -6872,8 +6871,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to set system decors flag to a display that does " - + "not exist: " + displayId); + ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that does " + + "not exist: %d", displayId); return; } if (displayContent.isUntrustedVirtualDisplay()) { @@ -6896,8 +6895,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to get IME flag of a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to get IME flag of a display that does not exist: %d", + displayId); return false; } if (displayContent.isUntrustedVirtualDisplay()) { @@ -6917,8 +6917,9 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null); if (displayContent == null) { - Slog.w(TAG_WM, "Attempted to set IME flag to a display that does not exist: " - + displayId); + ProtoLog.w(WM_ERROR, + "Attempted to set IME flag to a display that does not exist: %d", + displayId); return; } if (displayContent.isUntrustedVirtualDisplay()) { @@ -7135,15 +7136,16 @@ public class WindowManagerService extends IWindowManager.Stub if (removeWindows) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { - Slog.w(TAG_WM, "removeWindowToken: Attempted to remove token: " + binder - + " for non-exiting displayId=" + displayId); + ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s" + + " for non-exiting displayId=%d", binder, displayId); return; } final WindowToken token = dc.removeWindowToken(binder); if (token == null) { - Slog.w(TAG_WM, "removeWindowToken: Attempted to remove non-existing token: " - + binder); + ProtoLog.w(WM_ERROR, + "removeWindowToken: Attempted to remove non-existing token: %s", + binder); return; } @@ -7746,4 +7748,27 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(token); } } + + @Override + public boolean mirrorDisplay(int displayId, SurfaceControl outSurfaceControl) { + if (!checkCallingPermission(ACCESS_SURFACE_FLINGER, "mirrorDisplay()")) { + throw new SecurityException("Requires ACCESS_SURFACE_FLINGER permission"); + } + + final SurfaceControl displaySc; + synchronized (mGlobalLock) { + DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + Slog.e(TAG, "Invalid displayId " + displayId + " for mirrorDisplay"); + return false; + } + + displaySc = displayContent.getSurfaceControl(); + } + + final SurfaceControl mirror = SurfaceControl.mirrorSurface(displaySc); + outSurfaceControl.copyFrom(mirror); + + return true; + } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0a65e3240885..569d248d8efb 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -90,20 +90,20 @@ import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS; import static com.android.server.wm.MoveAnimationSpecProto.FROM; import static com.android.server.wm.MoveAnimationSpecProto.TO; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; @@ -197,6 +197,7 @@ import android.view.SurfaceSession; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowInfo; +import android.view.WindowInsets.Type.InsetType; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -206,6 +207,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.KeyInterceptionInfo; import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.utils.InsetUtils; import com.android.server.wm.utils.WmDisplayCutout; @@ -781,7 +783,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type); mIsChildWindow = true; - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow); parentWindow.addChild(this, sWindowSubLayerComparator); mLayoutAttached = mAttrs.type != @@ -1294,14 +1296,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP || configChanged || dragResizingChanged || mReportOrientationChanged) { - if (DEBUG_RESIZE || DEBUG_ORIENTATION) { - Slog.v(TAG_WM, "Resize reasons for w=" + this + ": " - + " " + mWindowFrames.getInsetsChangedInfo() - + " surfaceResized=" + winAnimator.mSurfaceResized - + " configChanged=" + configChanged - + " dragResizingChanged=" + dragResizingChanged - + " reportOrientationChanged=" + mReportOrientationChanged); - } + ProtoLog.v(WM_DEBUG_RESIZE, + "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b " + + "dragResizingChanged=%b reportOrientationChanged=%b", + this, mWindowFrames.getInsetsChangedInfo(), winAnimator.mSurfaceResized, + configChanged, dragResizingChanged, mReportOrientationChanged); // If it's a dead window left on screen, and the configuration changed, there is nothing // we can do about it. Remove the window now. @@ -1318,24 +1317,31 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // redrawn; to do that, we need to go through the process of getting informed by the // application when it has finished drawing. if (getOrientationChanging() || dragResizingChanged) { - if (DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) { - Slog.v(TAG_WM, "Orientation or resize start waiting for draw" + if (getOrientationChanging()) { + Slog.v(TAG_WM, "Orientation start waiting for draw" + ", mDrawState=DRAW_PENDING in " + this + ", surfaceController " + winAnimator.mSurfaceController); } + if (dragResizingChanged) { + ProtoLog.v(WM_DEBUG_RESIZE, + "Resize start waiting for draw, " + + "mDrawState=DRAW_PENDING in %s, surfaceController %s", + this, winAnimator.mSurfaceController); + } winAnimator.mDrawState = DRAW_PENDING; if (mAppToken != null) { mAppToken.clearAllDrawn(); } } if (!mWmService.mResizingWindows.contains(this)) { - if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this); + ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this); mWmService.mResizingWindows.add(this); } } else if (getOrientationChanging()) { if (isDrawnLw()) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in " - + this + ", surfaceController " + winAnimator.mSurfaceController); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Orientation not waiting for draw in %s, surfaceController %s", this, + winAnimator.mSurfaceController); setOrientationChanging(false); mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() - mWmService.mDisplayFreezeTime); @@ -1705,7 +1711,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onMovedByResize() { - if (DEBUG_RESIZE) Slog.d(TAG, "onMovedByResize: Moving " + this); + ProtoLog.d(WM_DEBUG_RESIZE, "onMovedByResize: Moving %s", this); mMovedByResize = true; super.onMovedByResize(); } @@ -1779,7 +1785,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void onResize() { final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows; if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) { - if (DEBUG_RESIZE) Slog.d(TAG, "onResize: Resizing " + this); + ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this); resizingWindows.add(this); } if (isGoneForLayoutLw()) { @@ -1922,8 +1928,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mRemoved) { // Nothing to do. - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "WS.removeImmediately: " + this + " Already removed..."); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "WS.removeImmediately: %s Already removed...", this); return; } @@ -1973,39 +1979,35 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private void removeIfPossible(boolean keepVisibleDeadWindow) { mWindowRemovalAllowed = true; - if (DEBUG_ADD_REMOVE) Slog.v(TAG, - "removeIfPossible: " + this + " callers=" + Debug.getCallers(5)); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "removeIfPossible: %s callers=%s", this, Debug.getCallers(5)); final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING; - if (startingWindow && DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, - "Starting window removed " + this); - - if (DEBUG || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && isFocused()) { - Slog.v(TAG_WM, "Remove " + this + " client=" - + Integer.toHexString(System.identityHashCode(mClient.asBinder())) - + ", surfaceController=" + mWinAnimator.mSurfaceController + " Callers=" - + Debug.getCallers(5)); + if (startingWindow) { + ProtoLog.d(WM_DEBUG_STARTING_WINDOW, "Starting window removed %s", this); } + ProtoLog.v(WM_DEBUG_FOCUS, "Remove client=%x, surfaceController=%s Callers=%s", + System.identityHashCode(mClient.asBinder()), + mWinAnimator.mSurfaceController, + Debug.getCallers(5)); + + final long origId = Binder.clearCallingIdentity(); try { disposeInputChannel(); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this - + ": mSurfaceController=" + mWinAnimator.mSurfaceController - + " mAnimatingExit=" + mAnimatingExit - + " mRemoveOnExit=" + mRemoveOnExit - + " mHasSurface=" + mHasSurface - + " surfaceShowing=" + mWinAnimator.getShown() - + " animating=" + isAnimating() - + " app-animation=" - + (mAppToken != null ? mAppToken.isSelfAnimating() : "false") - + " mWillReplaceWindow=" + mWillReplaceWindow - + " inPendingTransaction=" - + (mAppToken != null ? mAppToken.inPendingTransaction : false) - + " mDisplayFrozen=" + mWmService.mDisplayFrozen - + " callers=" + Debug.getCallers(6)); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b " + + "mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b " + + "mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b " + + "callers=%s", + this, mWinAnimator.mSurfaceController, mAnimatingExit, mRemoveOnExit, + mHasSurface, mWinAnimator.getShown(), isAnimating(), + mAppToken != null && mAppToken.isSelfAnimating(), mWillReplaceWindow, + mAppToken != null && mAppToken.inPendingTransaction, + mWmService.mDisplayFrozen, Debug.getCallers(6)); // Visibility of the removed window. Will be used later to update orientation later on. boolean wasVisible = false; @@ -2017,8 +2019,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mWillReplaceWindow) { // This window is going to be replaced. We need to keep it around until the new one // gets added, then we will get rid of this one. - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Preserving " + this + " until the new one is " + "added"); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "Preserving %s until the new one is added", this); // TODO: We are overloading mAnimatingExit flag to prevent the window state from // been removed. We probably need another flag to indicate that window removal // should be deffered vs. overloading the flag that says we are playing an exit @@ -2032,8 +2034,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP wasVisible = isWinVisibleLw(); if (keepVisibleDeadWindow) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Not removing " + this + " because app died while it's visible"); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "Not removing %s because app died while it's visible", this); mAppDied = true; setDisplayLayoutNeeded(); @@ -2074,8 +2076,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mWinAnimator.getShown() && mAnimatingExit && (!lastWindowIsStartingWindow || isAnimating)) { // The exit animation is running or should run... wait for it! - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Not removing " + this + " due to exit animation "); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "Not removing %s due to exit animation", this); setupWindowForRemoveOnExit(); if (mAppToken != null) { mAppToken.updateReportedVisibilityLocked(); @@ -2242,7 +2244,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } private void removeReplacedWindow() { - if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + this); + ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Removing replaced window: %s", this); mWillReplaceWindow = false; mAnimateReplacingWindow = false; mReplacingRemoveRequested = false; @@ -2398,7 +2400,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (!isVisibleByPolicy()) { mWinAnimator.hide("checkPolicyVisibilityChange"); if (isFocused()) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setAnimationLocked: setting mFocusMayChange true"); mWmService.mFocusMayChange = true; } @@ -2622,8 +2624,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** @return false if this window desires touch events. */ boolean cantReceiveTouchInput() { - return mAppToken != null && mAppToken.getTask() != null - && (mAppToken.getTask().mStack.shouldIgnoreInput() || mAppToken.hiddenRequested); + if (mAppToken == null || mAppToken.getTask() == null) { + return false; + } + + return mAppToken.getTask().mStack.shouldIgnoreInput() + || mAppToken.hiddenRequested + || isAnimatingToRecents(); + } + + /** + * Returns {@code true} if the window is animating to home as part of the recents animation. + */ + private boolean isAnimatingToRecents() { + final RecentsAnimationController recentsAnimationController = + mWmService.getRecentsAnimationController(); + return recentsAnimationController != null + && recentsAnimationController.isAnimatingTask(getTask()) + && !recentsAnimationController.isTargetApp(mAppToken); } @Override @@ -2721,7 +2739,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // we allow the display to be enabled now. mWmService.enableScreenIfNeededLocked(); if (isFocused) { - if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "WindowState.hideLw: setting mFocusMayChange true"); mWmService.mFocusMayChange = true; } @@ -2927,7 +2945,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mHasSurface && !getOrientationChanging() && mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "set mOrientationChanging of %s", this); setOrientationChanging(true); mWmService.mRoot.mOrientationChangeComplete = false; } @@ -2955,10 +2974,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } if (mDestroying) { - if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this - + " destroySurfaces: appStopped=" + appStopped - + " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed - + " win.mRemoveOnExit=" + mRemoveOnExit); + ProtoLog.e(WM_DEBUG_ADD_REMOVE, "win=%s" + + " destroySurfaces: appStopped=%b" + + " win.mWindowRemovalAllowed=%b" + + " win.mRemoveOnExit=%b", this, appStopped, + mWindowRemovalAllowed, mRemoveOnExit); if (!cleanupOnResume || mRemoveOnExit) { destroySurfaceUnchecked(); } @@ -3226,16 +3246,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void reportResized() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag()); try { - if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this - + ": " + mWindowFrames.mCompatFrame); + ProtoLog.v(WM_DEBUG_RESIZE, + "Reporting new frame to %s: %s", this, + mWindowFrames.mCompatFrame); final MergedConfiguration mergedConfiguration = new MergedConfiguration(mWmService.mRoot.getConfiguration(), getMergedOverrideConfiguration()); setLastReportedMergedConfiguration(mergedConfiguration); - if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING) - Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); + if (mWinAnimator.mDrawState == DRAW_PENDING) { + ProtoLog.i(WM_DEBUG_ORIENTATION, + "Resizing %s WITH DRAW PENDING", this); + } final Rect frame = mWindowFrames.mCompatFrame; final Rect overscanInsets = mWindowFrames.mLastOverscanInsets; @@ -3343,6 +3366,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + @Override + public void showInsets(@InsetType int types, boolean fromIme) { + try { + mClient.showInsets(types, fromIme); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver showInsets", e); + } + } + Rect getBackdropFrame(Rect frame) { // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing // start even if we haven't received the relayout window, so that the client requests @@ -4378,9 +4410,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } - if (DEBUG || DEBUG_ADD_REMOVE) { - Slog.v(TAG, "Exit animation finished in " + this + ": remove=" + mRemoveOnExit); - } + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Exit animation finished in %s: remove=%b", + this, mRemoveOnExit); mDestroying = true; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 8fccc8d02d6f..3dcf6ecb5124 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -27,17 +27,18 @@ import static android.view.WindowManager.TRANSIT_NONE; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_DRAW; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; @@ -67,6 +68,7 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; @@ -312,19 +314,19 @@ class WindowStateAnimator { boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) { final boolean startingWindow = mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; - if (DEBUG_STARTING_WINDOW && startingWindow) { - Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState=" - + drawStateToString()); + if (startingWindow) { + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finishing drawing window %s: mDrawState=%s", + mWin, drawStateToString()); } boolean layoutNeeded = false; if (mDrawState == DRAW_PENDING) { - if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) - Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in " - + mSurfaceController); - if (DEBUG_STARTING_WINDOW && startingWindow) { - Slog.v(TAG, "Draw state now committed in " + mWin); + ProtoLog.v(WM_DEBUG_DRAW, + "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", mWin, + mSurfaceController); + if (startingWindow) { + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Draw state now committed in %s", mWin); } mDrawState = COMMIT_DRAW_PENDING; layoutNeeded = true; @@ -385,7 +387,7 @@ class WindowStateAnimator { mSurfaceDestroyDeferred = true; return; } - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SET FREEZE LAYER: %s", mWin); if (mSurfaceController != null) { // Our SurfaceControl is always at layer 0 within the parent Surface managed by // window-state. We want this old Surface to stay on top of the new one @@ -456,8 +458,9 @@ class WindowStateAnimator { w.setHasSurface(false); - if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG, - "createSurface " + this + ": mDrawState=DRAW_PENDING"); + if (DEBUG_ANIM) { + Slog.i(TAG, "createSurface " + this + ": mDrawState=DRAW_PENDING"); + } resetDrawState(); @@ -514,15 +517,10 @@ class WindowStateAnimator { w.setHasSurface(true); - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - Slog.i(TAG, " CREATE SURFACE " - + mSurfaceController + " IN SESSION " - + mSession.mSurfaceSession - + ": pid=" + mSession.mPid + " format=" - + attrs.format + " flags=0x" - + Integer.toHexString(flags) - + " / " + this); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, + " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x / %s", + mSurfaceController, mSession.mSurfaceSession, mSession.mPid, attrs.format, + flags, this); } catch (OutOfResourcesException e) { Slog.w(TAG, "OutOfResourcesException creating surface"); mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true); @@ -616,17 +614,15 @@ class WindowStateAnimator { if (mSurfaceDestroyDeferred) { if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) { if (mPendingDestroySurface != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - WindowManagerService.logSurface(mWin, "DESTROY PENDING", true); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY PENDING: %s. %s", + mWin, new RuntimeException().fillInStackTrace()); mPendingDestroySurface.destroyNotInTransaction(); } mPendingDestroySurface = mSurfaceController; } } else { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - WindowManagerService.logSurface(mWin, "DESTROY", true); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s", + mWin, new RuntimeException().fillInStackTrace()); destroySurface(); } // Don't hide wallpaper if we're deferring the surface destroy @@ -653,9 +649,8 @@ class WindowStateAnimator { void destroyDeferredSurfaceLocked() { try { if (mPendingDestroySurface != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - WindowManagerService.logSurface(mWin, "DESTROY PENDING", true); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY PENDING: %s. %s", + mWin, new RuntimeException().fillInStackTrace()); mPendingDestroySurface.destroyNotInTransaction(); // Don't hide wallpaper if we're destroying a deferred surface // after a surface mode change. @@ -1088,9 +1083,7 @@ class WindowStateAnimator { // There is no need to wait for an animation change if our window is gone for layout // already as we'll never be visible. if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "Orientation change skips hidden " + w); - } + ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w); w.setOrientationChanging(false); } return; @@ -1115,8 +1108,8 @@ class WindowStateAnimator { // before it has drawn for the new orientation. if (w.getOrientationChanging() && w.isGoneForLayoutLw()) { w.setOrientationChanging(false); - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation change skips hidden " + w); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Orientation change skips hidden %s", w); } } else if (mLastAlpha != mShownAlpha || mLastDsDx != mDsDx @@ -1134,13 +1127,10 @@ class WindowStateAnimator { mLastDtDy = mDtDy; w.mLastHScale = w.mHScale; w.mLastVScale = w.mVScale; - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, - "controller=" + mSurfaceController + - "alpha=" + mShownAlpha - + " matrix=[" + mDsDx + "*" + w.mHScale - + "," + mDtDx + "*" + w.mVScale - + "][" + mDtDy + "*" + w.mHScale - + "," + mDsDy + "*" + w.mVScale + "]", false); + ProtoLog.i(WM_SHOW_TRANSACTIONS, + "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s", + mSurfaceController, mShownAlpha, mDsDx, w.mHScale, mDtDx, w.mVScale, + mDtDy, w.mHScale, mDsDy, w.mVScale, w); boolean prepared = mSurfaceController.prepareToShowInTransaction(mShownAlpha, @@ -1190,11 +1180,11 @@ class WindowStateAnimator { if (!w.isDrawnLw()) { mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE; mAnimator.mLastWindowFreezeSource = w; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation continue waiting for draw in " + w); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Orientation continue waiting for draw in %s", w); } else { w.setOrientationChanging(false); - if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w); + ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change complete in %s", w); } } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 6d813d106345..49f27a1b495d 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -21,10 +21,10 @@ import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW; import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowSurfaceControllerProto.LAYER; @@ -40,6 +40,8 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowContentFrameStats; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; class WindowSurfaceController { @@ -111,31 +113,22 @@ class WindowSurfaceController { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } - private void logSurface(String msg, RuntimeException where) { - String str = " SURFACE " + msg + ": " + title; - if (where != null) { - Slog.i(TAG, str, where); - } else { - Slog.i(TAG, str); - } - } - void reparentChildrenInTransaction(WindowSurfaceController other) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "REPARENT from: %s to: %s", this, other); if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) { mSurfaceControl.reparentChildren(other.mSurfaceControl); } } void detachChildren() { - if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN"); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SEVER CHILDREN"); if (mSurfaceControl != null) { mSurfaceControl.detachChildren(); } } void hide(SurfaceControl.Transaction transaction, String reason) { - if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE HIDE ( %s ): %s", reason, title); mHiddenForOtherReasons = true; mAnimator.destroyPreservedSurfaceLocked(); @@ -157,9 +150,8 @@ class WindowSurfaceController { } void destroyNotInTransaction() { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8)); - } + ProtoLog.i(WM_SHOW_SURFACE_ALLOC, + "Destroying surface %s called by %s", this, Debug.getCallers(8)); try { if (mSurfaceControl != null) { mTmpTransaction.remove(mSurfaceControl).apply(); @@ -173,8 +165,7 @@ class WindowSurfaceController { } void setCropInTransaction(Rect clipRect, boolean recoveringMemory) { - if (SHOW_TRANSACTIONS) logSurface( - "CROP " + clipRect.toShortString(), null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE CROP %s: %s", clipRect.toShortString(), title); try { if (clipRect.width() > 0 && clipRect.height() > 0) { if (!clipRect.equals(mSurfaceCrop)) { @@ -198,8 +189,7 @@ class WindowSurfaceController { } void clearCropInTransaction(boolean recoveringMemory) { - if (SHOW_TRANSACTIONS) logSurface( - "CLEAR CROP", null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE CLEAR CROP: %s", title); try { Rect clipRect = new Rect(0, 0, -1, -1); if (mSurfaceCrop.equals(clipRect)) { @@ -227,8 +217,8 @@ class WindowSurfaceController { mSurfaceY = top; try { - if (SHOW_TRANSACTIONS) logSurface( - "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, + "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", left, top, title); if (t == null) { mSurfaceControl.setPosition(left, top); @@ -264,8 +254,8 @@ class WindowSurfaceController { mLastDsdy = dsdy; try { - if (SHOW_TRANSACTIONS) logSurface( - "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE MATRIX [%f,%f,%f,%f]: %s", + dsdx, dtdx, dtdy, dsdy, title); if (t == null) { mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy); } else { @@ -290,8 +280,7 @@ class WindowSurfaceController { mSurfaceH = height; try { - if (SHOW_TRANSACTIONS) logSurface( - "SIZE " + width + "x" + height, null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SIZE %dx%d: %s", width, height, title); mSurfaceControl.setBufferSize(width, height); } catch (RuntimeException e) { // If something goes wrong with the surface (such @@ -350,8 +339,7 @@ class WindowSurfaceController { } void setOpaque(boolean isOpaque) { - if (SHOW_TRANSACTIONS) logSurface("isOpaque=" + isOpaque, - null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isOpaque=%b: %s", isOpaque, title); if (mSurfaceControl == null) { return; @@ -367,8 +355,7 @@ class WindowSurfaceController { } void setSecure(boolean isSecure) { - if (SHOW_TRANSACTIONS) logSurface("isSecure=" + isSecure, - null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, title); if (mSurfaceControl == null) { return; @@ -384,9 +371,7 @@ class WindowSurfaceController { } void setColorSpaceAgnostic(boolean agnostic) { - if (SHOW_TRANSACTIONS) { - logSurface("isColorSpaceAgnostic=" + agnostic, null); - } + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isColorSpaceAgnostic=%b: %s", agnostic, title); if (mSurfaceControl == null) { return; @@ -410,8 +395,7 @@ class WindowSurfaceController { } boolean showRobustlyInTransaction() { - if (SHOW_TRANSACTIONS) logSurface( - "SHOW (performLayout)", null); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SHOW (performLayout): %s", title); if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this + " during relayout"); mHiddenForOtherReasons = false; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 8aee0f2a8308..fbfb0286db1e 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -19,9 +19,9 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; @@ -35,9 +35,10 @@ import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER; import android.annotation.CallSuper; import android.os.Debug; import android.os.IBinder; -import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; import java.util.Comparator; @@ -135,8 +136,8 @@ class WindowToken extends WindowContainer<WindowState> { void removeAllWindowsIfPossible() { for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState win = mChildren.get(i); - if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, - "removeAllWindowsIfPossible: removing win=" + win); + ProtoLog.w(WM_DEBUG_WINDOW_MOVEMENT, + "removeAllWindowsIfPossible: removing win=%s", win); win.removeIfPossible(); } } @@ -197,15 +198,15 @@ class WindowToken extends WindowContainer<WindowState> { } void addWindow(final WindowState win) { - if (DEBUG_FOCUS) Slog.d(TAG_WM, - "addWindow: win=" + win + " Callers=" + Debug.getCallers(5)); + ProtoLog.d(WM_DEBUG_FOCUS, + "addWindow: win=%s Callers=%s", win, Debug.getCallers(5)); if (win.isChildWindow()) { // Child windows are added to their parent windows. return; } if (!mChildren.contains(win)) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this); addChild(win, mWindowComparator); mWmService.mWindowsChanged = true; // TODO: Should we also be setting layout needed here and other places? diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index d9c7fed0ff00..bcd1713222cb 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -141,6 +141,7 @@ 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 7aa9c7cce876..a8c76827c43c 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -16,17 +16,12 @@ #define LOG_TAG "VibratorService" -#include <android/hardware/vibrator/1.0/IVibrator.h> -#include <android/hardware/vibrator/1.0/types.h> -#include <android/hardware/vibrator/1.0/IVibrator.h> -#include <android/hardware/vibrator/1.1/types.h> -#include <android/hardware/vibrator/1.2/IVibrator.h> -#include <android/hardware/vibrator/1.2/types.h> -#include <android/hardware/vibrator/1.3/IVibrator.h> +#include <android/hardware/vibrator/1.4/IVibrator.h> #include "jni.h" #include <nativehelper/JNIHelp.h> #include "android_runtime/AndroidRuntime.h" +#include "core_jni_helpers.h" #include <utils/misc.h> #include <utils/Log.h> @@ -36,6 +31,7 @@ #include <stdio.h> using android::hardware::Return; +using android::hardware::Void; using android::hardware::vibrator::V1_0::EffectStrength; using android::hardware::vibrator::V1_0::Status; using android::hardware::vibrator::V1_1::Effect_1_1; @@ -44,9 +40,32 @@ 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 android { +static jmethodID sMethodIdOnComplete; + +class VibratorCallback : public V1_4::IVibratorCallback { + public: + VibratorCallback(JNIEnv *env, jobject vibration) : + mVibration(MakeGlobalRefOrDie(env, vibration)) {} + + ~VibratorCallback() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteGlobalRef(mVibration); + } + + Return<void> onComplete() override { + auto env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mVibration, sMethodIdOnComplete); + return Void(); + } + + private: + jobject mVibration; +}; + static constexpr int NUM_TRIES = 2; // Creates a Return<R> with STATUS::EX_NULL_POINTER. @@ -119,17 +138,17 @@ bool isValidEffect(jlong effect) { return val >= *iter.begin() && val <= *std::prev(iter.end()); } -static void vibratorInit(JNIEnv /* env */, jobject /* clazz */) +static void vibratorInit(JNIEnv *env, jclass clazz) { halCall(&V1_0::IVibrator::ping).isOk(); } -static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */) +static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) { return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE; } -static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms) +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) { @@ -137,7 +156,7 @@ static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms) } } -static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) +static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) { Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); if (retStatus != Status::OK) { @@ -145,11 +164,11 @@ static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) } } -static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) { +static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); } -static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) { +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) { @@ -158,11 +177,11 @@ static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) { } } -static jboolean vibratorSupportsExternalControl(JNIEnv*, jobject) { +static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); } -static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) { +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) { @@ -171,7 +190,8 @@ static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) { } } -static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) { +static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jint strength, + jobject vibration) { Status status; uint32_t lengthMs; auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { @@ -181,7 +201,11 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength EffectStrength effectStrength(static_cast<EffectStrength>(strength)); Return<void> ret; - if (isValidEffect<V1_0::Effect>(effect)) { + 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)) { @@ -218,6 +242,10 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength return -1; } +static jlong vibratorGetCapabilities(JNIEnv*, jclass) { + return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0); +} + static const JNINativeMethod method_table[] = { { "vibratorExists", "()Z", (void*)vibratorExists }, { "vibratorInit", "()V", (void*)vibratorInit }, @@ -225,13 +253,18 @@ static const JNINativeMethod method_table[] = { { "vibratorOff", "()V", (void*)vibratorOff }, { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl}, { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude}, - { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect}, + { "vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;)J", + (void*)vibratorPerformEffect}, { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl}, { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl}, + { "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities}, }; int register_android_server_VibratorService(JNIEnv *env) { + sMethodIdOnComplete = GetMethodIDOrDie(env, + FindClassOrDie(env, "com/android/server/VibratorService$Vibration"), + "onComplete", "()V"); return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table, NELEM(method_table)); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index f1142fd2f8f9..36e854ca77cd 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -46,7 +46,6 @@ import android.graphics.Point; import android.os.Handler; import android.os.Message; import android.os.RemoteException; -import android.util.Log; import android.view.Display; import android.view.InputDevice; import android.view.KeyEvent; @@ -55,6 +54,8 @@ import android.view.accessibility.AccessibilityEvent; import androidx.test.runner.AndroidJUnit4; +import com.android.server.accessibility.utils.MotionEventMatcher; + import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; @@ -761,56 +762,6 @@ public class MotionEventInjectorTest { return next; } - static class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> { - long mDownTime; - long mEventTime; - long mActionMasked; - int mX; - int mY; - - MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) { - mDownTime = downTime; - mEventTime = eventTime; - mActionMasked = actionMasked; - mX = x; - mY = y; - } - - MotionEventMatcher(MotionEvent event) { - this(event.getDownTime(), event.getEventTime(), event.getActionMasked(), - (int) event.getX(), (int) event.getY()); - } - - void offsetTimesBy(long timeOffset) { - mDownTime += timeOffset; - mEventTime += timeOffset; - } - - @Override - public boolean matchesSafely(MotionEvent event) { - if ((event.getDownTime() == mDownTime) && (event.getEventTime() == mEventTime) - && (event.getActionMasked() == mActionMasked) && ((int) event.getX() == mX) - && ((int) event.getY() == mY)) { - return true; - } - Log.e(LOG_TAG, "MotionEvent match failed"); - Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime() - + ", expected " + mDownTime); - Log.e(LOG_TAG, "event.getEventTime() = " + event.getEventTime() - + ", expected " + mEventTime); - Log.e(LOG_TAG, "event.getActionMasked() = " + event.getActionMasked() - + ", expected " + mActionMasked); - Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX); - Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY); - return false; - } - - @Override - public void describeTo(Description description) { - description.appendText("Motion event matcher"); - } - } - private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> { int mAction; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 104aacb5ef79..4b1ec6fe032b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -21,6 +21,7 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_DELEGAT import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING; import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; @@ -36,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.EventStreamTransformation; +import com.android.server.accessibility.utils.MotionEventMatcher; import org.junit.Before; import org.junit.Rule; @@ -49,6 +51,7 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public class TouchExplorerTest { + private static final String LOG_TAG = "TouchExplorerTest"; private static final int FLAG_1FINGER = 0x8000; private static final int FLAG_2FINGERS = 0x0100; private static final int FLAG_3FINGERS = 0x0200; @@ -86,7 +89,9 @@ public class TouchExplorerTest { @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent); mEvents.add(0, event.copy()); + assertThat(rawEvent, lastEventMatcher); } @Override diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java new file mode 100644 index 000000000000..2b6d385fed48 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java @@ -0,0 +1,88 @@ +/* + * 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.accessibility.utils; + +import android.util.Log; +import android.view.MotionEvent; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; + +/** + * This class compares two motion events using a subset of their attributes: actionMasked, downTime, + * eventTime, and location. If two events match they are considered to be effectively equal. + */ +public class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> { + private static final String LOG_TAG = "MotionEventMatcher"; + long mDownTime; + long mEventTime; + long mActionMasked; + int mX; + int mY; + + MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) { + mDownTime = downTime; + mEventTime = eventTime; + mActionMasked = actionMasked; + mX = x; + mY = y; + } + + public MotionEventMatcher(MotionEvent event) { + this( + event.getDownTime(), + event.getEventTime(), + event.getActionMasked(), + (int) event.getX(), + (int) event.getY()); + } + + void offsetTimesBy(long timeOffset) { + mDownTime += timeOffset; + mEventTime += timeOffset; + } + + @Override + public boolean matchesSafely(MotionEvent event) { + if ((event.getDownTime() == mDownTime) + && (event.getEventTime() == mEventTime) + && (event.getActionMasked() == mActionMasked) + && ((int) event.getX() == mX) + && ((int) event.getY() == mY)) { + return true; + } + Log.e(LOG_TAG, "MotionEvent match failed"); + Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime() + ", expected " + mDownTime); + Log.e( + LOG_TAG, + "event.getEventTime() = " + event.getEventTime() + ", expected " + mEventTime); + Log.e( + LOG_TAG, + "event.getActionMasked() = " + + event.getActionMasked() + + ", expected " + + mActionMasked); + Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX); + Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY); + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText("Motion event matcher"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index d4b7e7e913f6..79cc3db90fff 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -25,8 +25,8 @@ import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG; import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG; -import static com.android.server.am.UserController.SYSTEM_USER_CURRENT_MSG; -import static com.android.server.am.UserController.SYSTEM_USER_START_MSG; +import static com.android.server.am.UserController.USER_CURRENT_MSG; +import static com.android.server.am.UserController.USER_START_MSG; import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG; import static com.google.android.collect.Lists.newArrayList; @@ -53,11 +53,13 @@ import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.UserIdInt; import android.app.IUserSwitchObserver; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; import android.content.pm.UserInfo; +import android.content.pm.UserInfo.UserInfoFlag; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -106,6 +108,10 @@ public class UserControllerTest { private static final int TEST_USER_ID1 = 101; private static final int TEST_USER_ID2 = 102; private static final int NONEXIST_USER_ID = 2; + private static final int TEST_PRE_CREATED_USER_ID = 103; + + private static final int NO_USERINFO_FLAGS = 0; + private static final String TAG = UserControllerTest.class.getSimpleName(); private static final long HANDLER_WAIT_TIME_MS = 100; @@ -127,11 +133,11 @@ public class UserControllerTest { private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet( REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG, - SYSTEM_USER_START_MSG, - SYSTEM_USER_CURRENT_MSG); + USER_START_MSG, + USER_CURRENT_MSG); private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet( - SYSTEM_USER_START_MSG, + USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG); @Before @@ -148,7 +154,8 @@ public class UserControllerTest { doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt()); doNothing().when(mInjector).stackSupervisorRemoveUser(anyInt()); mUserController = new UserController(mInjector); - setUpUser(TEST_USER_ID, 0); + setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS); + setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true); }); } @@ -188,6 +195,31 @@ public class UserControllerTest { startForegroundUserAssertions(); } + @Test + public void testStartPreCreatedUser_foreground() { + assertFalse(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ true)); + } + + @Test + public void testStartPreCreatedUser_background() throws Exception { + assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ false)); + + verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt()); + verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean()); + verify(mInjector, never()).clearAllLockedTasks(anyString()); + + assertWithMessage("should not have received intents") + .that(getActions(mInjector.mSentIntents)).isEmpty(); + // TODO(b/140868593): should have received a USER_UNLOCK_MSG message as well, but it doesn't + // because StorageManager.isUserKeyUnlocked(TEST_PRE_CREATED_USER_ID) returns false - to + // properly fix it, we'd need to move this class to FrameworksMockingServicesTests so we can + // mock static methods (but moving this class would involve changing the presubmit tests, + // and the cascade effect goes on...). In fact, a better approach would to not assert the + // binder calls, but their side effects (in this case, that the user is stopped right away) + assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes()) + .containsExactly(USER_START_MSG); + } + private void startUserAssertions( List<String> expectedActions, Set<Integer> expectedMessageCodes) { assertEquals(expectedActions, getActions(mInjector.mSentIntents)); @@ -467,9 +499,15 @@ public class UserControllerTest { continueUserSwitchAssertions(newUserId, expectOldUserStopping); } - private void setUpUser(int userId, int flags) { + private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags) { + setUpUser(userId, flags, /* preCreated= */ false); + } + + private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags, boolean preCreated) { UserInfo userInfo = new UserInfo(userId, "User" + userId, flags); + userInfo.preCreated = preCreated; when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo); + when(mInjector.mUserManagerMock.isPreCreated(userId)).thenReturn(preCreated); } private static List<String> getActions(List<Intent> intents) { diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java new file mode 100644 index 000000000000..4321c21f68b2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java @@ -0,0 +1,66 @@ +/* + * 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.integrity.model; + +import static com.android.server.testutils.TestUtils.assertExpectException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class RuleTest { + + private static final Rule.Effect DENY_EFFECT = Rule.Effect.DENY; + private static final Rule.Formula SIMPLE_FORMULA = + new Rule.AtomicFormula(Rule.Key.PACKAGE_NAME, Rule.Operator.EQ, "com.test.app"); + + @Test + public void testEmptyRule() { + Rule emptyRule = Rule.EMPTY; + + assertNull(emptyRule.getFormula()); + assertNull(emptyRule.getEffect()); + } + + @Test + public void testValidRule() { + Rule validRule = new Rule(SIMPLE_FORMULA, DENY_EFFECT); + + assertEquals(SIMPLE_FORMULA, validRule.getFormula()); + assertEquals(DENY_EFFECT, validRule.getEffect()); + } + + @Test + public void testInvalidRule_invalidEffect() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(SIMPLE_FORMULA, null)); + } + + @Test + public void testInvalidRule_invalidFormula() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(null, DENY_EFFECT)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 7cece1f5cecc..f9ac02271a27 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -32,8 +32,11 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DeviceStateCache; import android.app.trust.TrustManager; import android.content.ComponentName; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.hardware.authsecret.V1_0.IAuthSecret; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; @@ -95,6 +98,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { RecoverableKeyStoreManager mRecoverableKeyStoreManager; UserManagerInternal mUserManagerInternal; DeviceStateCache mDeviceStateCache; + FingerprintManager mFingerprintManager; + FaceManager mFaceManager; + PackageManager mPackageManager; protected boolean mHasSecureLockScreen; @Override @@ -114,6 +120,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mRecoverableKeyStoreManager = mock(RecoverableKeyStoreManager.class); mUserManagerInternal = mock(UserManagerInternal.class); mDeviceStateCache = mock(DeviceStateCache.class); + mFingerprintManager = mock(FingerprintManager.class); + mFaceManager = mock(FaceManager.class); + mPackageManager = mock(PackageManager.class); LocalServices.removeServiceForTest(LockSettingsInternal.class); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); @@ -123,7 +132,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class), - mock(KeyguardManager.class)); + mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; @@ -181,6 +190,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { new ComponentName("com.dummy.package", ".FakeDeviceOwner")); when(mUserManagerInternal.isDeviceManaged()).thenReturn(true); when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true); + mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID); + mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID); mLocalService = LocalServices.getService(LockSettingsInternal.class); } @@ -233,6 +244,18 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { return sm; } + private void mockBiometricsHardwareFingerprintsAndTemplates(int userId) { + // Hardware must be detected and fingerprints must be enrolled + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFingerprintManager.hasEnrolledFingerprints(userId)).thenReturn(true); + + // Hardware must be detected and templates must be enrolled + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(userId)).thenReturn(true); + } + @Override protected void tearDown() throws Exception { super.tearDown(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 65d6f45b5c6c..fcd98e0742ea 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -23,7 +23,6 @@ import android.app.admin.DeviceStateCache; import android.content.Context; import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.Handler; -import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.UserManagerInternal; @@ -32,6 +31,7 @@ import android.security.KeyStore; import android.security.keystore.KeyPermanentlyInvalidatedException; import com.android.internal.widget.LockPatternUtils; +import com.android.server.ServiceThread; import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager; import java.io.FileNotFoundException; @@ -70,8 +70,8 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public Handler getHandler() { - return new Handler(Looper.getMainLooper()); + public Handler getHandler(ServiceThread handlerThread) { + return new Handler(handlerThread.getLooper()); } @Override diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 7354ad4b9ac3..5818133aa2a4 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -330,6 +330,27 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, MANAGED_PROFILE_USER_ID); } + public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException { + final String oldCredential = "oldPassword"; + + initializeStorageWithCredential( + PRIMARY_USER_ID, + oldCredential, + CREDENTIAL_TYPE_PATTERN, + PASSWORD_QUALITY_SOMETHING); + mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); + + mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, oldCredential.getBytes(), + PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false); + + // Verify fingerprint is removed + verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any()); + verify(mFaceManager).remove(any(), eq(PRIMARY_USER_ID), any()); + + verify(mFingerprintManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any()); + verify(mFaceManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any()); + } + public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials() throws Exception { final String parentPassword = "parentPassword"; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java index 8e0d7be5f44f..2a169b775ca3 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java @@ -24,8 +24,11 @@ import android.app.KeyguardManager; import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.sqlite.SQLiteDatabase; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.FileUtils; import android.os.SystemClock; import android.os.UserManager; @@ -86,7 +89,9 @@ public class LockSettingsStorageTests extends AndroidTestCase { MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager, mock(NotificationManager.class), mock(DevicePolicyManager.class), - mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class)); + mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class), + mock(FingerprintManager.class), mock(FaceManager.class), + mock(PackageManager.class)); mStorage = new LockSettingsStorageTestable(context, new File(getContext().getFilesDir(), "locksettings")); mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java index b33253264317..2b9a05c3ef63 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java @@ -23,6 +23,8 @@ import android.app.trust.TrustManager; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.PackageManager; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.UserManager; import android.os.storage.StorageManager; @@ -34,11 +36,15 @@ public class MockLockSettingsContext extends ContextWrapper { private StorageManager mStorageManager; private TrustManager mTrustManager; private KeyguardManager mKeyguardManager; + private FingerprintManager mFingerprintManager; + private FaceManager mFaceManager; + private PackageManager mPackageManager; public MockLockSettingsContext(Context base, UserManager userManager, NotificationManager notificationManager, DevicePolicyManager devicePolicyManager, StorageManager storageManager, TrustManager trustManager, - KeyguardManager keyguardManager) { + KeyguardManager keyguardManager, FingerprintManager fingerprintManager, + FaceManager faceManager, PackageManager packageManager) { super(base); mUserManager = userManager; mNotificationManager = notificationManager; @@ -46,6 +52,9 @@ public class MockLockSettingsContext extends ContextWrapper { mStorageManager = storageManager; mTrustManager = trustManager; mKeyguardManager = keyguardManager; + mFingerprintManager = fingerprintManager; + mFaceManager = faceManager; + mPackageManager = packageManager; } @Override @@ -62,12 +71,21 @@ public class MockLockSettingsContext extends ContextWrapper { return mTrustManager; } else if (KEYGUARD_SERVICE.equals(name)) { return mKeyguardManager; + } else if (FINGERPRINT_SERVICE.equals(name)) { + return mFingerprintManager; + } else if (FACE_SERVICE.equals(name)) { + return mFaceManager; } else { throw new RuntimeException("System service not mocked: " + name); } } @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + + @Override public void enforceCallingOrSelfPermission(String permission, String message) { // Skip permission checks for unit tests. } diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java new file mode 100644 index 000000000000..ee3b15a97f26 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java @@ -0,0 +1,318 @@ +/* + * 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.rollback; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.pm.VersionedPackage; +import android.content.rollback.PackageRollbackInfo; +import android.util.IntArray; +import android.util.SparseLongArray; + +import com.google.common.truth.Correspondence; + +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@RunWith(JUnit4.class) +public class RollbackStoreTest { + + private static final int ID = 123; + + private static final Correspondence<VersionedPackage, VersionedPackage> VER_PKG_CORR = + new Correspondence<VersionedPackage, VersionedPackage>() { + @Override + public boolean compare(VersionedPackage a, VersionedPackage b) { + if (a == null || b == null) { + return a == b; + } + return a.getLongVersionCode() == b.getLongVersionCode() + && Objects.equals(a.getPackageName(), b.getPackageName()); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + private static final Correspondence<PackageRollbackInfo.RestoreInfo, + PackageRollbackInfo.RestoreInfo> + RESTORE_INFO_CORR = + new Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo>() { + @Override + public boolean compare(PackageRollbackInfo.RestoreInfo a, + PackageRollbackInfo.RestoreInfo b) { + if (a == null || b == null) { + return a == b; + } + return a.userId == b.userId + && a.appId == b.appId + && Objects.equals(a.seInfo, b.seInfo); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + private static final String JSON_ROLLBACK = "{'info':{'rollbackId':123,'packages':" + + "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55}," + + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':" + + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'}," + + "{'userId':-895,'appId':1,'seInfo':'pingu'}],'isApex':false,'installedUsers':" + + "[498468432,1111,98464],'ceSnapshotInodes':[{'userId':1,'ceSnapshotInode':-6}," + + "{'userId':2222,'ceSnapshotInode':81641654445},{'userId':546546," + + "'ceSnapshotInode':345689375}]},{'versionRolledBackFrom':{'packageName':'chips'," + + "'longVersionCode':28},'versionRolledBackTo':{'packageName':'com.chips.test'," + + "'longVersionCode':48},'pendingBackups':[5],'pendingRestores':[{'userId':18," + + "'appId':-12,'seInfo':''}],'isApex':false,'installedUsers':[55,79]," + + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello'," + + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}]," + + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z'," + + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1," + + "'restoreUserDataInProgress':true}"; + + @Rule + public TemporaryFolder mFolder = new TemporaryFolder(); + + private File mRollbackDir; + + private RollbackStore mRollbackStore; + + @Before + public void setUp() throws Exception { + mRollbackStore = new RollbackStore(mFolder.getRoot()); + mRollbackDir = mFolder.newFolder(ID + ""); + mFolder.newFile("rollback.json"); + } + + @Test + public void createNonStaged() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isFalse(); + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void createStaged() { + Rollback rollback = mRollbackStore.createStagedRollback(ID, 897); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isTrue(); + assertThat(rollback.getStagedSessionId()).isEqualTo(897); + + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void saveAndLoadRollback() { + Rollback origRb = mRollbackStore.createNonStagedRollback(ID); + + origRb.setRestoreUserDataInProgress(true); + origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); + origRb.info.getCausePackages().add(new VersionedPackage("com.pack.age", 99)); + origRb.info.setCommittedSessionId(123456); + + PackageRollbackInfo pkgInfo1 = + new PackageRollbackInfo(new VersionedPackage("com.made.up", 18), + new VersionedPackage("com.something.else", 5), new IntArray(), + new ArrayList<>(), false, new IntArray(), new SparseLongArray()); + pkgInfo1.getPendingBackups().add(8); + pkgInfo1.getPendingBackups().add(888); + pkgInfo1.getPendingBackups().add(88885); + pkgInfo1.getCeSnapshotInodes().put(12, 424); + pkgInfo1.getCeSnapshotInodes().put(222772, 10000000000L); + pkgInfo1.getCeSnapshotInodes().put(10, -67); + + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(4980, 3442322, "seInfo")); + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(-89, 15, "otherSeInfo")); + + pkgInfo1.getSnapshottedUsers().add(11); + pkgInfo1.getSnapshottedUsers().add(1); + pkgInfo1.getSnapshottedUsers().add(0); + + PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo( + new VersionedPackage("another.package", 2), + new VersionedPackage("com.test.ing", 48888), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo2.getPendingBackups().add(57); + + pkgInfo2.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(180, -120, "")); + + origRb.info.getPackages().add(pkgInfo1); + origRb.info.getPackages().add(pkgInfo2); + + RollbackStore.saveRollback(origRb); + + List<Rollback> loadedRollbacks = mRollbackStore.loadRollbacks(); + assertThat(loadedRollbacks).hasSize(1); + Rollback loadedRb = loadedRollbacks.get(0); + + assertRollbacksAreEquivalent(loadedRb, origRb); + } + + @Test + public void loadFromJson() throws Exception { + Rollback expectedRb = mRollbackStore.createNonStagedRollback(ID); + + expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z")); + expectedRb.setRestoreUserDataInProgress(true); + expectedRb.info.getCausePackages().add(new VersionedPackage("hello", 23)); + expectedRb.info.getCausePackages().add(new VersionedPackage("something", 999)); + expectedRb.info.setCommittedSessionId(45654465); + + PackageRollbackInfo pkgInfo1 = new PackageRollbackInfo(new VersionedPackage("blah", 55), + new VersionedPackage("blah1", 50), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo1.getPendingBackups().add(59); + pkgInfo1.getPendingBackups().add(1245); + pkgInfo1.getPendingBackups().add(124544); + pkgInfo1.getCeSnapshotInodes().put(546546, 345689375); + pkgInfo1.getCeSnapshotInodes().put(2222, 81641654445L); + pkgInfo1.getCeSnapshotInodes().put(1, -6); + + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(498, 32322, "wombles")); + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(-895, 1, "pingu")); + + pkgInfo1.getSnapshottedUsers().add(498468432); + pkgInfo1.getSnapshottedUsers().add(1111); + pkgInfo1.getSnapshottedUsers().add(98464); + + PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo(new VersionedPackage("chips", 28), + new VersionedPackage("com.chips.test", 48), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo2.getPendingBackups().add(5); + + pkgInfo2.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(18, -12, "")); + + pkgInfo2.getSnapshottedUsers().add(55); + pkgInfo2.getSnapshottedUsers().add(79); + + expectedRb.info.getPackages().add(pkgInfo1); + expectedRb.info.getPackages().add(pkgInfo2); + + Rollback parsedRb = RollbackStore.rollbackFromJson( + new JSONObject(JSON_ROLLBACK), expectedRb.getBackupDir()); + + assertRollbacksAreEquivalent(parsedRb, expectedRb); + } + + @Test + public void saveAndDelete() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + RollbackStore.saveRollback(rollback); + + File expectedFile = new File(mRollbackDir.getAbsolutePath() + "/rollback.json"); + + assertThat(expectedFile.exists()).isTrue(); + + RollbackStore.deleteRollback(rollback); + + assertThat(expectedFile.exists()).isFalse(); + } + + private void assertRollbacksAreEquivalent(Rollback b, Rollback a) { + assertThat(b.info.getRollbackId()).isEqualTo(ID); + + assertThat(b.getBackupDir()).isEqualTo(a.getBackupDir()); + + assertThat(b.isRestoreUserDataInProgress()) + .isEqualTo(a.isRestoreUserDataInProgress()); + + assertThat(b.getTimestamp()).isEqualTo(a.getTimestamp()); + + assertThat(b.isEnabling()).isEqualTo(a.isEnabling()); + assertThat(b.isAvailable()).isEqualTo(a.isAvailable()); + assertThat(b.isCommitted()).isEqualTo(a.isCommitted()); + + assertThat(b.isStaged()).isEqualTo(a.isStaged()); + + assertThat(b.getApexPackageNames()) + .containsExactlyElementsIn(a.getApexPackageNames()); + + assertThat(b.getStagedSessionId()).isEqualTo(a.getStagedSessionId()); + + assertThat(b.info.getCommittedSessionId()).isEqualTo(a.info.getCommittedSessionId()); + + assertThat(b.info.getCausePackages()).comparingElementsUsing(VER_PKG_CORR) + .containsExactlyElementsIn(a.info.getCausePackages()); + + assertThat(b.info.getPackages()).hasSize(a.info.getPackages().size()); + + for (int i = 0; i < b.info.getPackages().size(); i++) { + assertPackageRollbacksAreEquivalent( + b.info.getPackages().get(i), a.info.getPackages().get(i)); + } + } + + private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) { + assertThat(b.getPackageName()).isEqualTo(a.getPackageName()); + + assertThat(b.getVersionRolledBackFrom().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackFrom().getLongVersionCode()); + assertThat(b.getVersionRolledBackFrom().getPackageName()) + .isEqualTo(a.getVersionRolledBackFrom().getPackageName()); + + assertThat(b.getVersionRolledBackTo().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackTo().getLongVersionCode()); + assertThat(b.getVersionRolledBackTo().getPackageName()) + .isEqualTo(a.getVersionRolledBackTo().getPackageName()); + + assertThat(b.getPendingBackups().toArray()).isEqualTo(a.getPendingBackups().toArray()); + + assertThat(b.getPendingRestores()).comparingElementsUsing(RESTORE_INFO_CORR) + .containsExactlyElementsIn(a.getPendingRestores()); + + assertThat(b.isApex()).isEqualTo(a.isApex()); + + assertThat(b.getSnapshottedUsers().toArray()).isEqualTo(a.getSnapshottedUsers().toArray()); + + assertThat(b.getCeSnapshotInodes().toString()) + .isEqualTo(a.getCeSnapshotInodes().toString()); + } + +} 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 ae4074275b97..ade0b146dd9a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -39,6 +39,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; @@ -46,6 +47,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; @@ -396,6 +398,59 @@ public class DisplayContentTests extends WindowTestsBase { mWm.mRoot.getTopFocusedDisplayContent().getDisplayId()); } + @Test + public void testShouldWaitForSystemDecorWindowsOnBoot_OnDefaultDisplay() { + mWm.mSystemBooted = true; + final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked(); + final WindowState[] windows = createNotDrawnWindowsOn(defaultDisplay, + TYPE_WALLPAPER, TYPE_APPLICATION); + + // Verify waiting for windows to be drawn. + assertTrue(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify not waiting for drawn windows. + makeWindowsDrawn(windows); + assertFalse(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + } + + @Test + public void testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay() { + mWm.mSystemBooted = true; + final DisplayContent secondaryDisplay = createNewDisplay(); + final WindowState[] windows = createNotDrawnWindowsOn(secondaryDisplay, + TYPE_WALLPAPER, TYPE_APPLICATION); + + // Verify not waiting for display without system decorations. + doReturn(false).when(secondaryDisplay).supportsSystemDecorations(); + assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify waiting for non-drawn windows on display with system decorations. + reset(secondaryDisplay); + doReturn(true).when(secondaryDisplay).supportsSystemDecorations(); + assertTrue(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + + // Verify not waiting for drawn windows on display with system decorations. + makeWindowsDrawn(windows); + assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot()); + } + + private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) { + final WindowState[] windows = new WindowState[types.length]; + for (int i = 0; i < types.length; i++) { + final int type = types[i]; + windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type); + windows[i].mHasSurface = false; + } + return windows; + } + + private static void makeWindowsDrawn(WindowState[] windows) { + for (WindowState window : windows) { + window.mHasSurface = true; + window.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; + } + } + /** * This tests setting the maximum ui width on a display. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 059ff3d70660..480c4681de0c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -68,6 +68,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.utils.WmDisplayCutout; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -122,6 +123,12 @@ public class DisplayRotationTests { sMockWm.mPolicy = mock(WindowManagerPolicy.class); } + @AfterClass + public static void tearDownOnce() { + // Make sure the fake settings are cleared after the last test method. + FakeSettingsProvider.clearSettingsProvider(); + } + @Before public void setUp() { FakeSettingsProvider.clearSettingsProvider(); @@ -238,18 +245,58 @@ public class DisplayRotationTests { } @Test - public void testReturnsUserRotation_UserRotationLocked_CompatibleAppRequest() + public void testReturnsLandscape_UserRotationLockedSeascape_AppRequestsLandscape() throws Exception { mBuilder.build(); - configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */, + false /* isTv */); freezeRotation(Surface.ROTATION_180); - assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90)); } @Test + public void testReturnsSeascape_UserRotationLockedSeascape_AppRequestsSeascape() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */, + false /* isTv */); + + freezeRotation(Surface.ROTATION_180); + + assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, Surface.ROTATION_90)); + } + + @Test + public void testReturnsPortrait_UserRotationLockedPortrait_AppRequestsPortrait() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */, + false /* isTv */); + + freezeRotation(Surface.ROTATION_270); + + assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_0)); + } + + @Test + public void testReturnsUpsideDown_UserRotationLockedUpsideDown_AppRequestsUpsideDown() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */, + false /* isTv */); + + freezeRotation(Surface.ROTATION_90); + + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, Surface.ROTATION_0)); + } + + @Test public void testReturnsSideways_UserRotationLocked_IncompatibleAppRequest() throws Exception { mBuilder.build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 94abd346a814..445a5cc50d51 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -63,7 +63,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; -import android.util.MutableLong; import android.util.SparseBooleanArray; import androidx.test.filters.MediumTest; @@ -72,6 +71,7 @@ import com.android.server.wm.RecentTasks.Callbacks; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.util.ArrayList; @@ -86,6 +86,7 @@ import java.util.Set; */ @MediumTest @Presubmit +@RunWith(WindowTestRunner.class) public class RecentTasksTest extends ActivityTestsBase { private static final int TEST_USER_0_ID = 0; private static final int TEST_USER_1_ID = 10; @@ -95,10 +96,7 @@ public class RecentTasksTest extends ActivityTestsBase { private static final int INVALID_STACK_ID = 999; private ActivityDisplay mDisplay; - private ActivityDisplay mOtherDisplay; - private ActivityDisplay mSingleTaskDisplay; private ActivityStack mStack; - private ActivityStack mHomeStack; private TestTaskPersister mTaskPersister; private TestRecentTasks mRecentTasks; private TestRunningTasks mRunningTasks; @@ -111,15 +109,7 @@ public class RecentTasksTest extends ActivityTestsBase { @Before public void setUp() throws Exception { mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); - - // Set testing displays mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY); - mOtherDisplay = createNewActivityDisplay(); - mSingleTaskDisplay = createNewActivityDisplay(); - mSingleTaskDisplay.setDisplayToSingleTaskInstance(); - mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); - mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP); - mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP); // Set the recent tasks we should use for testing in this class. mRecentTasks = new TestRecentTasks(mService, mTaskPersister); @@ -131,8 +121,6 @@ public class RecentTasksTest extends ActivityTestsBase { mRunningTasks = new TestRunningTasks(); mService.mStackSupervisor.setRunningTasks(mRunningTasks); - mHomeStack = mDisplay.getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mStack = mDisplay.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mCallbacksRecorder = new CallbacksRecorder(); @@ -269,7 +257,7 @@ public class RecentTasksTest extends ActivityTestsBase { // other task TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) - .setStack(mHomeStack).build(); + .setStack(mDisplay.getHomeStack()).build(); TaskRecord task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) .setStack(mStack).build(); @@ -446,12 +434,12 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(task3); mRecentTasks.add(task4); - MutableLong prevLastActiveTime = new MutableLong(0); + long prevLastActiveTime = 0; final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks(); for (int i = 0; i < tasks.size(); i++) { final TaskRecord task = tasks.get(i); - assertThat(prevLastActiveTime.value).isLessThan(task.lastActiveTime); - prevLastActiveTime.value = task.lastActiveTime; + assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime); + prevLastActiveTime = task.lastActiveTime; } } @@ -618,7 +606,10 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); - ActivityStack singleTaskStack = mSingleTaskDisplay.createStack( + final ActivityDisplay singleTaskDisplay = + addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + singleTaskDisplay.setDisplayToSingleTaskInstance(); + ActivityStack singleTaskStack = singleTaskDisplay.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1") @@ -795,7 +786,8 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); final ActivityStack homeStack = mDisplay.getHomeStack(); - final ActivityStack otherDisplayStack = mOtherDisplay.createStack( + final ActivityDisplay otherDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); + final ActivityStack otherDisplayStack = otherDisplay.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index e6c9b9f7a160..dd85f69b7160 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -29,6 +29,8 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; @@ -65,6 +67,10 @@ import java.util.Locale; @SmallTest @Presubmit public class TaskLaunchParamsModifierTests extends ActivityTestsBase { + private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0, + /* right */ 1920, /* bottom */ 1080); + private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100, + /* top */ 200, /* right */ 1620, /* bottom */ 680); private ActivityRecord mActivity; @@ -614,7 +620,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(0, mResult.mBounds.left); + assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left); } @Test @@ -630,7 +636,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(0, mResult.mBounds.top); + assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top); } @Test @@ -646,8 +652,8 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(0, mResult.mBounds.left); - assertEquals(0, mResult.mBounds.top); + assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left); + assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top); } @Test @@ -663,7 +669,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(1920, mResult.mBounds.right); + assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right); } @Test @@ -679,7 +685,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(1080, mResult.mBounds.bottom); + assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom); } @Test @@ -695,8 +701,8 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(1920, mResult.mBounds.right); - assertEquals(1080, mResult.mBounds.bottom); + assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right); + assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom); } @Test @@ -712,7 +718,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds); + assertEquals(new Rect(800, 400, 920, 480), mResult.mBounds); } @Test @@ -728,7 +734,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds); + assertEquals(new Rect(100, 400, 220, 480), mResult.mBounds); } @Test @@ -744,7 +750,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds); + assertEquals(new Rect(800, 200, 920, 280), mResult.mBounds); } @Test @@ -760,7 +766,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds); + assertEquals(new Rect(100, 200, 220, 280), mResult.mBounds); } @Test @@ -776,7 +782,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds); + assertEquals(new Rect(1500, 400, 1620, 480), mResult.mBounds); } @Test @@ -792,7 +798,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds); + assertEquals(new Rect(800, 600, 920, 680), mResult.mBounds); } @Test @@ -808,7 +814,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds); + assertEquals(new Rect(1500, 600, 1620, 680), mResult.mBounds); } @Test @@ -819,12 +825,12 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId; final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder() - .setWidthFraction(0.0625f).setHeightFraction(0.1f).build(); + .setWidthFraction(0.125f).setHeightFraction(0.1f).build(); assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); - assertEquals(new Rect(900, 486, 1020, 594), mResult.mBounds); + assertEquals(new Rect(765, 416, 955, 464), mResult.mBounds); } @Test @@ -952,13 +958,12 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, mActivity, /* source */ null, options, mCurrent, mResult)); - final Rect displayBounds = freeformDisplay.getBounds(); assertEquals("Distance to left and right should be equal.", - mResult.mBounds.left - displayBounds.left, - displayBounds.right - mResult.mBounds.right); + mResult.mBounds.left - DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.right - mResult.mBounds.right, /* delta */ 1); assertEquals("Distance to top and bottom should be equal.", - mResult.mBounds.top - displayBounds.top, - displayBounds.bottom - mResult.mBounds.bottom); + mResult.mBounds.top - DISPLAY_STABLE_BOUNDS.top, + DISPLAY_STABLE_BOUNDS.bottom - mResult.mBounds.bottom, /* delta */ 1); } @Test @@ -1041,15 +1046,16 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { options.setLaunchDisplayId(freeformDisplay.mDisplayId); mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM; - mCurrent.mBounds.set(100, 200, 2120, 1380); + mCurrent.mBounds.set(100, 300, 1820, 1380); mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, mActivity, /* source */ null, options, mCurrent, mResult)); - assertTrue("Result bounds should start from origin, but it's " + mResult.mBounds, - mResult.mBounds.left == 0 && mResult.mBounds.top == 0); + assertTrue("Result bounds should start from app bounds's origin, but it's " + + mResult.mBounds, + mResult.mBounds.left == 100 && mResult.mBounds.top == 200); } @Test @@ -1067,15 +1073,16 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { options.setLaunchDisplayId(freeformDisplay.mDisplayId); mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM; - mCurrent.mBounds.set(100, 200, 2120, 1380); + mCurrent.mBounds.set(100, 300, 1820, 1380); mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, mActivity, /* source */ null, options, mCurrent, mResult)); - assertTrue("Result bounds should start from origin, but it's " + mResult.mBounds, - mResult.mBounds.left == -100 && mResult.mBounds.top == 0); + assertTrue("Result bounds should start from top-right corner of app bounds, but " + + "it's " + mResult.mBounds, + mResult.mBounds.left == -100 && mResult.mBounds.top == 200); } @Test @@ -1083,6 +1090,11 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { final TestActivityDisplay freeformDisplay = createNewActivityDisplay( WINDOWING_MODE_FREEFORM); + // This test case requires a relatively big app bounds to ensure the default size calculated + // by letterbox won't be too small to hold the minimum width/height. + freeformDisplay.mDisplayContent.mDisplayFrames.mStable.set(/* left */ 10, /* top */ 10, + /* right */ 1910, /* top */ 1070); + final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(freeformDisplay.mDisplayId); @@ -1245,7 +1257,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, mActivity, /* source */ null, options, mCurrent, mResult)); - assertEquals(new Rect(0, 0, 300, 300), mResult.mBounds); + assertEquals(new Rect(100, 200, 400, 500), mResult.mBounds); } @Test @@ -1301,9 +1313,15 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { private TestActivityDisplay createNewActivityDisplay(int windowingMode) { final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); display.setWindowingMode(windowingMode); - display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080); + display.setBounds(DISPLAY_BOUNDS); display.getConfiguration().densityDpi = DENSITY_DEFAULT; display.getConfiguration().orientation = ORIENTATION_LANDSCAPE; + display.mDisplayContent.mDisplayFrames.mStable.set(DISPLAY_STABLE_BOUNDS); + spyOn(display.mDisplayContent.mDisplayFrames); + + // We didn't set up the overall environment for this test, so we need to mute the side + // effect of layout passes that loosen the stable frame. + doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout(); return display; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java index a7586810a824..09e5027c1faa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java @@ -111,4 +111,8 @@ public class TestIWindow extends IWindow.Stub { @Override public void dispatchPointerCaptureChanged(boolean hasCapture) { } + + @Override + public void showInsets(int types, boolean fromIme) throws RemoteException { + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index f41f126593de..0503d74b38d5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -57,6 +57,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; import android.graphics.Insets; import android.graphics.Matrix; @@ -547,4 +548,29 @@ public class WindowStateTests extends WindowTestsBase { assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f); assertEquals(0f, values[Matrix.MTRANS_Y], 0f); } + + @Test + public void testCantReceiveTouchDuringRecentsAnimation() { + final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); + + // Mock active recents animation + RecentsAnimationController recentsController = mock(RecentsAnimationController.class); + when(recentsController.isAnimatingTask(win0.mAppToken.getTask())).thenReturn(true); + mWm.setRecentsAnimationController(recentsController); + assertTrue(win0.cantReceiveTouchInput()); + } + + @Test + public void testCantReceiveTouchWhenAppTokenHiddenRequested() { + final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); + win0.mAppToken.hiddenRequested = true; + assertTrue(win0.cantReceiveTouchInput()); + } + + @Test + public void testCantReceiveTouchWhenShouldIgnoreInput() { + final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); + win0.mAppToken.getStack().setAdjustedForMinimizedDock(1 /* Any non 0 value works */); + assertTrue(win0.cantReceiveTouchInput()); + } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index e3183e3a8344..59d07357ff56 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -977,7 +977,9 @@ public class UsageStatsService extends SystemService implements continue; } UserUsageStatsService service = mUserState.get(userId); - service.persistActiveStats(); + if (service != null) { + service.persistActiveStats(); + } mAppStandby.flushToDisk(userId); } mAppStandby.flushDurationsToDisk(); diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index e899dff5e5a2..047fcecd5a5b 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -386,7 +386,7 @@ public class UsbHostManager { return false; } - UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDevice(); + UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDeviceBuilder(); if (newDeviceBuilder == null) { Slog.e(TAG, "Couldn't create UsbDevice object."); // Tracking diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 6ffbd43a7b1a..8e7babb40fc0 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -309,17 +309,17 @@ public final class UsbDescriptorParser { /** * @hide */ - public UsbDevice.Builder toAndroidUsbDevice() { + public UsbDevice.Builder toAndroidUsbDeviceBuilder() { if (mDeviceDescriptor == null) { Log.e(TAG, "toAndroidUsbDevice() ERROR - No Device Descriptor"); return null; } - UsbDevice.Builder device = mDeviceDescriptor.toAndroid(this); - if (device == null) { + UsbDevice.Builder builder = mDeviceDescriptor.toAndroid(this); + if (builder == null) { Log.e(TAG, "toAndroidUsbDevice() ERROR Creating Device"); } - return device; + return builder; } /** @@ -524,6 +524,37 @@ public final class UsbDescriptorParser { /** * @hide */ + public boolean hasAudioTerminal(int subType) { + for (UsbDescriptor descriptor : mDescriptors) { + if (descriptor instanceof UsbACInterface) { + if (((UsbACInterface) descriptor).getSubclass() + == UsbDescriptor.AUDIO_AUDIOCONTROL + && ((UsbACInterface) descriptor).getSubtype() + == subType) { + return true; + } + } + } + return false; + } + + /** + * @hide + */ + public boolean hasAudioPlayback() { + return hasAudioTerminal(UsbACInterface.ACI_OUTPUT_TERMINAL); + } + + /** + * @hide + */ + public boolean hasAudioCapture() { + return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL); + } + + /** + * @hide + */ public boolean hasHIDInterface() { ArrayList<UsbDescriptor> descriptors = getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java index e6e10fef9f9a..9735502a4f69 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java @@ -156,11 +156,10 @@ public final class UsbDeviceDescriptor extends UsbDescriptor { for (int index = 0; index < mConfigDescriptors.size(); index++) { configs[index] = mConfigDescriptors.get(index).toAndroid(parser); } - UsbDevice.Builder device = new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID, - mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString, - configs, serialStr); - return device; + return new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID, + mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString, + configs, serialStr, parser.hasAudioPlayback(), parser.hasAudioCapture()); } @Override diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 1822cee89eaa..5e71416a0510 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -19,6 +19,7 @@ package android.telecom; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; @@ -119,6 +120,20 @@ public final class Call { public static final int STATE_PULLING_CALL = 11; /** + * The state of a call that is active with the network, but the audio from the call is + * being intercepted by an app on the local device. Telecom does not hold audio focus in this + * state, and the call will be invisible to the user except for a persistent notification. + */ + public static final int STATE_AUDIO_PROCESSING = 12; + + /** + * The state of a call that is being presented to the user after being in + * {@link #STATE_AUDIO_PROCESSING}. The call is still active with the network in this case, and + * Telecom will hold audio focus and play a ringtone if appropriate. + */ + public static final int STATE_SIMULATED_RINGING = 13; + + /** * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call * extras. Used to pass the phone accounts to display on the front end to the user in order to * select phone accounts to (for example) place a call. @@ -1479,6 +1494,49 @@ public final class Call { } /** + * Instructs Telecom to put the call into the background audio processing state. + * + * This method can be called either when the call is in {@link #STATE_RINGING} or + * {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to + * {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in + * order to capture and play audio on the call stream. + * + * This method can only be called by the default dialer app. + * @hide + */ + @SystemApi + @TestApi + //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO) + public void enterBackgroundAudioProcessing() { + if (mState != STATE_ACTIVE && mState != STATE_RINGING) { + throw new IllegalStateException("Call must be active or ringing"); + } + mInCallAdapter.enterBackgroundAudioProcessing(mTelecomCallId); + } + + /** + * Instructs Telecom to come out of the background audio processing state requested by + * {@link #enterBackgroundAudioProcessing()} or from the call screening service. + * + * This method can only be called when the call is in {@link #STATE_AUDIO_PROCESSING}. + * + * @param shouldRing If true, Telecom will put the call into the + * {@link #STATE_SIMULATED_RINGING} state and notify other apps that there is + * a ringing call. Otherwise, the call will go into {@link #STATE_ACTIVE} + * immediately. + * @hide + */ + @SystemApi + @TestApi + //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO) + public void exitBackgroundAudioProcessing(boolean shouldRing) { + if (mState != STATE_AUDIO_PROCESSING) { + throw new IllegalStateException("Call must in the audio processing state"); + } + mInCallAdapter.exitBackgroundAudioProcessing(mTelecomCallId, shouldRing); + } + + /** * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. * * Any other currently playing DTMF tone in the specified call is immediately stopped. diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index e4f8d118e7df..0d97567ed213 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -18,6 +18,8 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Service; import android.content.ComponentName; import android.content.Intent; @@ -136,23 +138,30 @@ public abstract class CallScreeningService extends Service { private final boolean mShouldSilenceCall; private final boolean mShouldSkipCallLog; private final boolean mShouldSkipNotification; + private final boolean mShouldScreenCallFurther; private CallResponse( boolean shouldDisallowCall, boolean shouldRejectCall, boolean shouldSilenceCall, boolean shouldSkipCallLog, - boolean shouldSkipNotification) { + boolean shouldSkipNotification, + boolean shouldScreenCallFurther) { if (!shouldDisallowCall && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) { throw new IllegalStateException("Invalid response state for allowed call."); } + if (shouldDisallowCall && shouldScreenCallFurther) { + throw new IllegalStateException("Invalid response state for allowed call."); + } + mShouldDisallowCall = shouldDisallowCall; mShouldRejectCall = shouldRejectCall; mShouldSkipCallLog = shouldSkipCallLog; mShouldSkipNotification = shouldSkipNotification; mShouldSilenceCall = shouldSilenceCall; + mShouldScreenCallFurther = shouldScreenCallFurther; } /* @@ -191,12 +200,22 @@ public abstract class CallScreeningService extends Service { return mShouldSkipNotification; } + /** + * @return Whether we should enter the {@link Call#STATE_AUDIO_PROCESSING} state to allow + * for further screening of the call. + * @hide + */ + public boolean getShouldScreenCallFurther() { + return mShouldScreenCallFurther; + } + public static class Builder { private boolean mShouldDisallowCall; private boolean mShouldRejectCall; private boolean mShouldSilenceCall; private boolean mShouldSkipCallLog; private boolean mShouldSkipNotification; + private boolean mShouldScreenCallFurther; /** * Sets whether the incoming call should be blocked. @@ -252,13 +271,32 @@ public abstract class CallScreeningService extends Service { return this; } + /** + * Sets whether to request background audio processing so that the in-call service can + * screen the call further. If set to {@code true}, {@link #setDisallowCall} should be + * called with {@code false}, and all other parameters in this builder will be ignored. + * + * This request will only be honored if the {@link CallScreeningService} shares the same + * uid as the default dialer app. Otherwise, the call will go through as usual. + * + * @param shouldScreenCallFurther Whether to request further call screening. + * @hide + */ + @SystemApi + @TestApi + public Builder setShouldScreenCallFurther(boolean shouldScreenCallFurther) { + mShouldScreenCallFurther = shouldScreenCallFurther; + return this; + } + public CallResponse build() { return new CallResponse( mShouldDisallowCall, mShouldRejectCall, mShouldSilenceCall, mShouldSkipCallLog, - mShouldSkipNotification); + mShouldSkipNotification, + mShouldScreenCallFurther); } } } diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index cd5fd971a065..d90f46dcf326 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -24,6 +24,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.telecom.Connection.VideoProvider; +import android.telephony.Annotation.RilRadioTechnology; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -687,7 +688,7 @@ public abstract class Conference extends Conferenceable { * * @hide */ - public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) { + public final void setCallRadioTech(@RilRadioTechnology int vrat) { putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE, ServiceState.rilRadioTechnologyToNetworkType(vrat)); } @@ -700,7 +701,7 @@ public abstract class Conference extends Conferenceable { * * @hide */ - public final @ServiceState.RilRadioTechnology int getCallRadioTech() { + public final @RilRadioTechnology int getCallRadioTech() { int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; Bundle extras = getExtras(); if (extras != null) { diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 0983eea8e819..525b938b7632 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -34,6 +34,7 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemClock; +import android.telephony.Annotation.RilRadioTechnology; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -1958,7 +1959,7 @@ public abstract class Connection extends Conferenceable { * * @hide */ - public final @ServiceState.RilRadioTechnology int getCallRadioTech() { + public final @RilRadioTechnology int getCallRadioTech() { int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; Bundle extras = getExtras(); if (extras != null) { @@ -2409,7 +2410,7 @@ public abstract class Connection extends Conferenceable { * * @hide */ - public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) { + public final void setCallRadioTech(@RilRadioTechnology int vrat) { putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE, ServiceState.rilRadioTechnologyToNetworkType(vrat)); // Propagates the call radio technology to its parent {@link android.telecom.Conference} diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 8678e33f68b6..261246818f1d 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -16,8 +16,8 @@ package android.telecom; -import android.net.Uri; import android.bluetooth.BluetoothDevice; +import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; @@ -149,6 +149,26 @@ public final class InCallAdapter { } /** + * @see Call#enterBackgroundAudioProcessing() + */ + public void enterBackgroundAudioProcessing(String callId) { + try { + mAdapter.enterBackgroundAudioProcessing(callId); + } catch (RemoteException e) { + } + } + + /** + * @see Call#exitBackgroundAudioProcessing(boolean) + */ + public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) { + try { + mAdapter.exitBackgroundAudioProcessing(callId, shouldRing); + } catch (RemoteException e) { + } + } + + /** * Request audio routing to a specific bluetooth device. Calling this method may result in * the device routing audio to a different bluetooth device than the one specified. A list of * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()} diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index f7ae9b1705ad..2bc20d51113a 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -2060,12 +2060,13 @@ public class TelecomManager { /** * Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity. * @param intent The {@link Intent#ACTION_CALL} intent to handle. + * @param callingPackageProxy The original package that called this before it was trampolined. * @hide */ - public void handleCallIntent(Intent intent) { + public void handleCallIntent(Intent intent, String callingPackageProxy) { try { if (isServiceConnected()) { - getTelecomService().handleCallIntent(intent); + getTelecomService().handleCallIntent(intent, callingPackageProxy); } } catch (RemoteException e) { Log.e(TAG, "RemoteException handleCallIntent: " + e); diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl index 3ee3285793c4..83c8f62bb3db 100644 --- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl @@ -30,6 +30,8 @@ oneway interface ICallScreeningAdapter { void silenceCall(String callId); + void screenCallFurther(String callId); + void disallowCall( String callId, boolean shouldReject, diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 57df5c1e548e..60745e40aa77 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -44,6 +44,10 @@ oneway interface IInCallAdapter { void setAudioRoute(int route, String bluetoothAddress); + void enterBackgroundAudioProcessing(String callId); + + void exitBackgroundAudioProcessing(String callId, boolean shouldRing); + void playDtmfTone(String callId, char digit); void stopDtmfTone(String callId); diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 704749844c19..6a1b78fb79cf 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -282,6 +282,11 @@ interface ITelecomService { void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct); /** + * @see TelecomServiceImpl#setTestEmergencyPhoneAccountPackageNameFilter + */ + void setTestEmergencyPhoneAccountPackageNameFilter(String packageName); + + /** * @see TelecomServiceImpl#isInEmergencyCall */ boolean isInEmergencyCall(); @@ -289,7 +294,7 @@ interface ITelecomService { /** * @see TelecomServiceImpl#handleCallIntent */ - void handleCallIntent(in Intent intent); + void handleCallIntent(in Intent intent, in String callingPackageProxy); void setTestDefaultCallRedirectionApp(String packageName); @@ -302,9 +307,9 @@ interface ITelecomService { void setTestAutoModeApp(String packageName); /** - * @see TelecomServiceImpl#setSystemDialerPackage + * @see TelecomServiceImpl#setSystemDialer */ - void setSystemDialerPackage(in String packageName); + void setSystemDialer(in ComponentName testComponentName); /** * @see TelecomServiceImpl#setTestDefaultDialer diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index a884a7039d5b..72f758eba39a 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -469,4 +469,44 @@ public class Annotation { @Retention(RetentionPolicy.SOURCE) public @interface DataFailureCause { } + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"PRECISE_CALL_STATE_"}, + value = { + PreciseCallState.PRECISE_CALL_STATE_NOT_VALID, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + PreciseCallState.PRECISE_CALL_STATE_HOLDING, + PreciseCallState.PRECISE_CALL_STATE_DIALING, + PreciseCallState.PRECISE_CALL_STATE_ALERTING, + PreciseCallState. PRECISE_CALL_STATE_INCOMING, + PreciseCallState.PRECISE_CALL_STATE_WAITING, + PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED, + PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING}) + public @interface PreciseCallStates {} + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"RIL_RADIO_TECHNOLOGY_" }, value = { + ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN, + ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, + ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, + ServiceState.RIL_RADIO_TECHNOLOGY_UMTS, + ServiceState.RIL_RADIO_TECHNOLOGY_IS95A, + ServiceState.RIL_RADIO_TECHNOLOGY_IS95B, + ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT, + ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0, + ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A, + ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA, + ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA, + ServiceState.RIL_RADIO_TECHNOLOGY_HSPA, + ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B, + ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, + ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP, + ServiceState.RIL_RADIO_TECHNOLOGY_GSM, + ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA, + ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, + ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA, + ServiceState.RIL_RADIO_TECHNOLOGY_NR}) + public @interface RilRadioTechnology {} } diff --git a/telephony/java/android/telephony/IFinancialSmsCallback.aidl b/telephony/java/android/telephony/IFinancialSmsCallback.aidl deleted file mode 100644 index aa88615c15cf..000000000000 --- a/telephony/java/android/telephony/IFinancialSmsCallback.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/* -** 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 android.telephony; - -import android.app.PendingIntent; -import android.database.CursorWindow; -import android.net.Uri; -import android.os.Bundle; -import com.android.internal.telephony.SmsRawData; - -/** Interface for returning back the financial sms messages asynchrously. - * @hide - */ -interface IFinancialSmsCallback { - /** - * Return sms messages back to calling financial app. - * - * @param messages the sms messages returned for cinancial app. - */ - oneway void onGetSmsMessagesForFinancialApp(in CursorWindow messages); -} diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java index da4da79a39df..45deea206cfc 100644 --- a/telephony/java/android/telephony/MbmsDownloadSession.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -243,6 +243,7 @@ public class MbmsDownloadSession implements AutoCloseable { }; private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null); + private ServiceConnection mServiceConnection; private final InternalDownloadSessionCallback mInternalCallback; private final Map<DownloadStatusListener, InternalDownloadStatusListener> mInternalDownloadStatusListeners = new HashMap<>(); @@ -318,56 +319,66 @@ public class MbmsDownloadSession implements AutoCloseable { } private int bindAndInitialize() { - return MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, - new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - IMbmsDownloadService downloadService = - IMbmsDownloadService.Stub.asInterface(service); - int result; - try { - result = downloadService.initialize(mSubscriptionId, mInternalCallback); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Service died before initialization"); - sIsInitialized.set(false); - return; - } catch (RuntimeException e) { - Log.e(LOG_TAG, "Runtime exception during initialization"); - sendErrorToApp( - MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - sIsInitialized.set(false); - return; - } - if (result == MbmsErrors.UNKNOWN) { - // Unbind and throw an obvious error - close(); - throw new IllegalStateException("Middleware must not return an" - + " unknown error code"); - } - if (result != MbmsErrors.SUCCESS) { - sendErrorToApp(result, "Error returned during initialization"); - sIsInitialized.set(false); - return; - } - try { - downloadService.asBinder().linkToDeath(mDeathRecipient, 0); - } catch (RemoteException e) { - sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, - "Middleware lost during initialization"); - sIsInitialized.set(false); - return; - } - mService.set(downloadService); - } + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMbmsDownloadService downloadService = + IMbmsDownloadService.Stub.asInterface(service); + int result; + try { + result = downloadService.initialize(mSubscriptionId, mInternalCallback); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Service died before initialization"); + sIsInitialized.set(false); + return; + } catch (RuntimeException e) { + Log.e(LOG_TAG, "Runtime exception during initialization"); + sendErrorToApp( + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); + return; + } + if (result == MbmsErrors.UNKNOWN) { + // Unbind and throw an obvious error + close(); + throw new IllegalStateException("Middleware must not return an" + + " unknown error code"); + } + if (result != MbmsErrors.SUCCESS) { + sendErrorToApp(result, "Error returned during initialization"); + sIsInitialized.set(false); + return; + } + try { + downloadService.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware lost during initialization"); + sIsInitialized.set(false); + return; + } + mService.set(downloadService); + } - @Override - public void onServiceDisconnected(ComponentName name) { - Log.w(LOG_TAG, "bindAndInitialize: Remote service disconnected"); - sIsInitialized.set(false); - mService.set(null); - } - }); + @Override + public void onServiceDisconnected(ComponentName name) { + Log.w(LOG_TAG, "bindAndInitialize: Remote service disconnected"); + sIsInitialized.set(false); + mService.set(null); + } + + @Override + public void onNullBinding(ComponentName name) { + Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null"); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware service binding returned null"); + sIsInitialized.set(false); + mService.set(null); + mContext.unbindService(this); + } + }; + return MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, mServiceConnection); } /** @@ -965,17 +976,19 @@ public class MbmsDownloadSession implements AutoCloseable { public void close() { try { IMbmsDownloadService downloadService = mService.get(); - if (downloadService == null) { + if (downloadService == null || mServiceConnection == null) { Log.i(LOG_TAG, "Service already dead"); return; } downloadService.dispose(mSubscriptionId); + mContext.unbindService(mServiceConnection); } catch (RemoteException e) { // Ignore Log.i(LOG_TAG, "Remote exception while disposing of service"); } finally { mService.set(null); sIsInitialized.set(false); + mServiceConnection = null; mInternalCallback.stop(); } } diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java index f1be31fa5477..d54071f28be9 100644 --- a/telephony/java/android/telephony/MbmsGroupCallSession.java +++ b/telephony/java/android/telephony/MbmsGroupCallSession.java @@ -80,6 +80,7 @@ public class MbmsGroupCallSession implements AutoCloseable { }; private InternalGroupCallSessionCallback mInternalCallback; + private ServiceConnection mServiceConnection; private Set<GroupCall> mKnownActiveGroupCalls = new ArraySet<>(); private final Context mContext; @@ -163,7 +164,7 @@ public class MbmsGroupCallSession implements AutoCloseable { public void close() { try { IMbmsGroupCallService groupCallService = mService.get(); - if (groupCallService == null) { + if (groupCallService == null || mServiceConnection == null) { // Ignore and return, assume already disposed. return; } @@ -172,11 +173,13 @@ public class MbmsGroupCallSession implements AutoCloseable { s.getCallback().stop(); } mKnownActiveGroupCalls.clear(); + mContext.unbindService(mServiceConnection); } catch (RemoteException e) { // Ignore for now } finally { mService.set(null); sIsInitialized.set(false); + mServiceConnection = null; mInternalCallback.stop(); } } @@ -244,59 +247,69 @@ public class MbmsGroupCallSession implements AutoCloseable { } private int bindAndInitialize() { - return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION, - new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - IMbmsGroupCallService groupCallService = - IMbmsGroupCallService.Stub.asInterface(service); - int result; - try { - result = groupCallService.initialize(mInternalCallback, - mSubscriptionId); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Service died before initialization"); - mInternalCallback.onError( - MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - sIsInitialized.set(false); - return; - } catch (RuntimeException e) { - Log.e(LOG_TAG, "Runtime exception during initialization"); - mInternalCallback.onError( - MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - sIsInitialized.set(false); - return; - } - if (result == MbmsErrors.UNKNOWN) { - // Unbind and throw an obvious error - close(); - throw new IllegalStateException("Middleware must not return" - + " an unknown error code"); - } - if (result != MbmsErrors.SUCCESS) { - mInternalCallback.onError(result, - "Error returned during initialization"); - sIsInitialized.set(false); - return; - } - try { - groupCallService.asBinder().linkToDeath(mDeathRecipient, 0); - } catch (RemoteException e) { - mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, - "Middleware lost during initialization"); - sIsInitialized.set(false); - return; - } - mService.set(groupCallService); - } + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMbmsGroupCallService groupCallService = + IMbmsGroupCallService.Stub.asInterface(service); + int result; + try { + result = groupCallService.initialize(mInternalCallback, + mSubscriptionId); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Service died before initialization"); + mInternalCallback.onError( + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); + return; + } catch (RuntimeException e) { + Log.e(LOG_TAG, "Runtime exception during initialization"); + mInternalCallback.onError( + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); + return; + } + if (result == MbmsErrors.UNKNOWN) { + // Unbind and throw an obvious error + close(); + throw new IllegalStateException("Middleware must not return" + + " an unknown error code"); + } + if (result != MbmsErrors.SUCCESS) { + mInternalCallback.onError(result, + "Error returned during initialization"); + sIsInitialized.set(false); + return; + } + try { + groupCallService.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware lost during initialization"); + sIsInitialized.set(false); + return; + } + mService.set(groupCallService); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + sIsInitialized.set(false); + mService.set(null); + } - @Override - public void onServiceDisconnected(ComponentName name) { - sIsInitialized.set(false); - mService.set(null); - } - }); + @Override + public void onNullBinding(ComponentName name) { + Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null"); + mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware service binding returned null"); + sIsInitialized.set(false); + mService.set(null); + mContext.unbindService(this); + } + }; + return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION, mServiceConnection); } } diff --git a/telephony/java/android/telephony/MbmsStreamingSession.java b/telephony/java/android/telephony/MbmsStreamingSession.java index cd465d22d331..3fbbc03f0c67 100644 --- a/telephony/java/android/telephony/MbmsStreamingSession.java +++ b/telephony/java/android/telephony/MbmsStreamingSession.java @@ -82,6 +82,7 @@ public class MbmsStreamingSession implements AutoCloseable { }; private InternalStreamingSessionCallback mInternalCallback; + private ServiceConnection mServiceConnection; private Set<StreamingService> mKnownActiveStreamingServices = new ArraySet<>(); private final Context mContext; @@ -168,7 +169,7 @@ public class MbmsStreamingSession implements AutoCloseable { public void close() { try { IMbmsStreamingService streamingService = mService.get(); - if (streamingService == null) { + if (streamingService == null || mServiceConnection == null) { // Ignore and return, assume already disposed. return; } @@ -177,11 +178,13 @@ public class MbmsStreamingSession implements AutoCloseable { s.getCallback().stop(); } mKnownActiveStreamingServices.clear(); + mContext.unbindService(mServiceConnection); } catch (RemoteException e) { // Ignore for now } finally { mService.set(null); sIsInitialized.set(false); + mServiceConnection = null; mInternalCallback.stop(); } } @@ -286,59 +289,69 @@ public class MbmsStreamingSession implements AutoCloseable { } private int bindAndInitialize() { - return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, - new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - IMbmsStreamingService streamingService = - IMbmsStreamingService.Stub.asInterface(service); - int result; - try { - result = streamingService.initialize(mInternalCallback, - mSubscriptionId); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Service died before initialization"); - sendErrorToApp( - MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - sIsInitialized.set(false); - return; - } catch (RuntimeException e) { - Log.e(LOG_TAG, "Runtime exception during initialization"); - sendErrorToApp( - MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - sIsInitialized.set(false); - return; - } - if (result == MbmsErrors.UNKNOWN) { - // Unbind and throw an obvious error - close(); - throw new IllegalStateException("Middleware must not return" - + " an unknown error code"); - } - if (result != MbmsErrors.SUCCESS) { - sendErrorToApp(result, "Error returned during initialization"); - sIsInitialized.set(false); - return; - } - try { - streamingService.asBinder().linkToDeath(mDeathRecipient, 0); - } catch (RemoteException e) { - sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, - "Middleware lost during initialization"); - sIsInitialized.set(false); - return; - } - mService.set(streamingService); - } + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMbmsStreamingService streamingService = + IMbmsStreamingService.Stub.asInterface(service); + int result; + try { + result = streamingService.initialize(mInternalCallback, + mSubscriptionId); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Service died before initialization"); + sendErrorToApp( + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); + return; + } catch (RuntimeException e) { + Log.e(LOG_TAG, "Runtime exception during initialization"); + sendErrorToApp( + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); + return; + } + if (result == MbmsErrors.UNKNOWN) { + // Unbind and throw an obvious error + close(); + throw new IllegalStateException("Middleware must not return" + + " an unknown error code"); + } + if (result != MbmsErrors.SUCCESS) { + sendErrorToApp(result, "Error returned during initialization"); + sIsInitialized.set(false); + return; + } + try { + streamingService.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware lost during initialization"); + sIsInitialized.set(false); + return; + } + mService.set(streamingService); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + sIsInitialized.set(false); + mService.set(null); + } - @Override - public void onServiceDisconnected(ComponentName name) { - sIsInitialized.set(false); - mService.set(null); - } - }); + @Override + public void onNullBinding(ComponentName name) { + Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null"); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, + "Middleware service binding returned null"); + sIsInitialized.set(false); + mService.set(null); + mContext.unbindService(this); + } + }; + return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, mServiceConnection); } private void sendErrorToApp(int errorCode, String message) { diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 57348979e8b1..c2028f900508 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -184,7 +184,8 @@ public class PhoneStateListener { public static final int LISTEN_CELL_INFO = 0x00000400; /** - * Listen for {@link PreciseCallState.State} of ringing, background and foreground calls. + * Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing, + * background and foreground calls. * * @hide */ diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java index f929649453b9..9f75332c4a03 100644 --- a/telephony/java/android/telephony/PreciseCallState.java +++ b/telephony/java/android/telephony/PreciseCallState.java @@ -23,6 +23,7 @@ import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.PreciseCallStates; import android.telephony.DisconnectCause; import android.telephony.PreciseDisconnectCause; @@ -48,22 +49,6 @@ import java.util.Objects; @SystemApi public final class PreciseCallState implements Parcelable { - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"PRECISE_CALL_STATE_"}, - value = { - PRECISE_CALL_STATE_NOT_VALID, - PRECISE_CALL_STATE_IDLE, - PRECISE_CALL_STATE_ACTIVE, - PRECISE_CALL_STATE_HOLDING, - PRECISE_CALL_STATE_DIALING, - PRECISE_CALL_STATE_ALERTING, - PRECISE_CALL_STATE_INCOMING, - PRECISE_CALL_STATE_WAITING, - PRECISE_CALL_STATE_DISCONNECTED, - PRECISE_CALL_STATE_DISCONNECTING}) - public @interface State {} - /** Call state is not valid (Not received a call state). */ public static final int PRECISE_CALL_STATE_NOT_VALID = -1; /** Call state: No activity. */ @@ -85,9 +70,9 @@ public final class PreciseCallState implements Parcelable { /** Call state: Disconnecting. */ public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; - private @State int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID; - private @State int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID; - private @State int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID; + private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID; + private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID; + private @PreciseCallStates int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID; private int mDisconnectCause = DisconnectCause.NOT_VALID; private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID; @@ -97,8 +82,9 @@ public final class PreciseCallState implements Parcelable { * @hide */ @UnsupportedAppUsage - public PreciseCallState(@State int ringingCall, @State int foregroundCall, - @State int backgroundCall, int disconnectCause, + public PreciseCallState(@PreciseCallStates int ringingCall, + @PreciseCallStates int foregroundCall, + @PreciseCallStates int backgroundCall, int disconnectCause, int preciseDisconnectCause) { mRingingCallState = ringingCall; mForegroundCallState = foregroundCall; @@ -131,21 +117,21 @@ public final class PreciseCallState implements Parcelable { /** * Returns the precise ringing call state. */ - public @State int getRingingCallState() { + public @PreciseCallStates int getRingingCallState() { return mRingingCallState; } /** * Returns the precise foreground call state. */ - public @State int getForegroundCallState() { + public @PreciseCallStates int getForegroundCallState() { return mForegroundCallState; } /** * Returns the precise background call state. */ - public @State int getBackgroundCallState() { + public @PreciseCallStates int getBackgroundCallState() { return mBackgroundCallState; } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index c57512973c3d..8587be7579e6 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -30,6 +30,7 @@ import android.os.Parcelable; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation.RilRadioTechnology; import android.telephony.NetworkRegistrationInfo.Domain; import android.telephony.NetworkRegistrationInfo.NRState; import android.text.TextUtils; @@ -155,32 +156,6 @@ public class ServiceState implements Parcelable { */ public static final int DUPLEX_MODE_TDD = 2; - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" }, - value = { - RIL_RADIO_TECHNOLOGY_UNKNOWN, - RIL_RADIO_TECHNOLOGY_GPRS, - RIL_RADIO_TECHNOLOGY_EDGE, - RIL_RADIO_TECHNOLOGY_UMTS, - RIL_RADIO_TECHNOLOGY_IS95A, - RIL_RADIO_TECHNOLOGY_IS95B, - RIL_RADIO_TECHNOLOGY_1xRTT, - RIL_RADIO_TECHNOLOGY_EVDO_0, - RIL_RADIO_TECHNOLOGY_EVDO_A, - RIL_RADIO_TECHNOLOGY_HSDPA, - RIL_RADIO_TECHNOLOGY_HSUPA, - RIL_RADIO_TECHNOLOGY_HSPA, - RIL_RADIO_TECHNOLOGY_EVDO_B, - RIL_RADIO_TECHNOLOGY_EHRPD, - RIL_RADIO_TECHNOLOGY_LTE, - RIL_RADIO_TECHNOLOGY_HSPAP, - RIL_RADIO_TECHNOLOGY_GSM, - RIL_RADIO_TECHNOLOGY_TD_SCDMA, - RIL_RADIO_TECHNOLOGY_IWLAN, - RIL_RADIO_TECHNOLOGY_LTE_CA, - RIL_RADIO_TECHNOLOGY_NR}) - public @interface RilRadioTechnology {} /** * Available radio technologies for GSM, UMTS and CDMA. * Duplicates the constants from hardware/radio/include/ril.h diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 5c39da7003a9..f4330fa0b725 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -32,8 +32,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; -import android.os.BaseBundle; import android.os.Binder; +import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; @@ -2081,7 +2081,9 @@ public final class SmsManager { } } - /** callback for providing asynchronous sms messages for financial app. */ + /** + * callback for providing asynchronous sms messages for financial app. + */ public abstract static class FinancialSmsCallback { /** * Callback to send sms messages back to financial app asynchronously. @@ -2107,24 +2109,14 @@ public final class SmsManager { * @param params the parameters to filter SMS messages returned. * @param executor the executor on which callback will be invoked. * @param callback a callback to receive CursorWindow with SMS messages. + * */ @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp( Bundle params, @NonNull @CallbackExecutor Executor executor, @NonNull FinancialSmsCallback callback) { - try { - ISms iccSms = getISmsServiceOrThrow(); - iccSms.getSmsMessagesForFinancialApp( - getSubscriptionId(), ActivityThread.currentPackageName(), params, - new IFinancialSmsCallback.Stub() { - public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) { - Binder.withCleanCallingIdentity(() -> executor.execute( - () -> callback.onFinancialSmsMessages(msgs))); - }}); - } catch (RemoteException ex) { - ex.rethrowFromSystemServer(); - } + // This API is not functional and thus removed to avoid future confusion. } /** @@ -2209,74 +2201,6 @@ public final class SmsManager { } } - /** - * Filters a bundle to only contain MMS config variables. - * - * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS - * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the - * supplied bundle. - * - * @param config a Bundle that contains MMS config variables and possibly more. - * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above. - * @hide - */ - public static Bundle getMmsConfig(BaseBundle config) { - Bundle filtered = new Bundle(); - filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID, - config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID)); - filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED)); - filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED, - config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED)); - filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED, - config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED)); - filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED)); - filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO, - config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO)); - filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED, - config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED)); - filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED, - config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED)); - filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, - config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION)); - filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES, - config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES)); - filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED, - config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED)); - filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED, - config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED)); - filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION, - config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION)); - filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE)); - filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH)); - filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT)); - filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT)); - filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS)); - filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS)); - filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, - config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD)); - filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD, - config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD)); - filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE, - config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE)); - filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH, - config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH)); - filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT, - config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT)); - filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME, - config.getString(MMS_CONFIG_UA_PROF_TAG_NAME)); - filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT)); - filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL)); - filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS)); - filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER, - config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER)); - filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX)); - filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS, - config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS)); - filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER, - config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER)); - return filtered; - } - /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"SMS_CATEGORY_"}, diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index bbf01d8f960b..a89328836e2a 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2101,13 +2101,26 @@ public class SubscriptionManager { /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static boolean isValidSlotIndex(int slotIndex) { - return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount(); + return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getMaxPhoneCount(); } /** @hide */ @UnsupportedAppUsage public static boolean isValidPhoneId(int phoneId) { - return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); + return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getMaxPhoneCount(); + } + + /** + * When getPhoneCount and getMaxPhoneCount return different value, isValidPhoneId being true + * doesn't mean the phoneId has a corresponding active slot / logical modem. If a DSDS capable + * device is in single SIM mode, phoneId=1 is valid but not active. + * + * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects + * are dynamically allocated instead of always based on getMaxPhoneCount. + * @hide + */ + public static boolean isActivePhoneId(int slotIndex) { + return slotIndex < TelephonyManager.getDefault().getPhoneCount(); } /** @hide */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 915ff6b1a839..f3215d4d0e8b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -399,7 +399,7 @@ public class TelephonyManager { * TODO: b/139642279 publicize and rename. * @hide */ - public static int getMaxPhoneCount() { + public int getMaxPhoneCount() { // TODO: b/139642279 when turning on this feature, remove dependency of // PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE and always return result based on // PROPERTY_MAX_ACTIVE_MODEMS. @@ -408,9 +408,9 @@ public class TelephonyManager { if (rebootRequired.equals("false")) { // If no reboot is required, return max possible active modems. return SystemProperties.getInt( - TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getDefault().getPhoneCount()); + TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getPhoneCount()); } else { - return getDefault().getPhoneCount(); + return getPhoneCount(); } } @@ -2444,7 +2444,14 @@ public class TelephonyManager { * @return the lowercase 2 character ISO-3166 country code, or empty string if not available. */ public String getNetworkCountryIso() { - return getNetworkCountryIso(getPhoneId()); + try { + ITelephony telephony = getITelephony(); + if (telephony == null) return ""; + return telephony.getNetworkCountryIsoForPhone(getPhoneId(), + null /* no permission check */); + } catch (RemoteException ex) { + return ""; + } } /** @@ -2470,11 +2477,12 @@ public class TelephonyManager { @SystemApi @TestApi @NonNull + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int slotIndex) { try { ITelephony telephony = getITelephony(); if (telephony == null) return ""; - return telephony.getNetworkCountryIsoForPhone(slotIndex); + return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName()); } catch (RemoteException ex) { return ""; } diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index 19d07242132b..16662652847d 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -18,6 +18,7 @@ package android.telephony.emergency; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.TestApi; import android.hardware.radio.V1_4.EmergencyNumberSource; import android.hardware.radio.V1_4.EmergencyServiceCategory; import android.os.Parcel; @@ -184,6 +185,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * * @hide */ + @TestApi public static final int EMERGENCY_NUMBER_SOURCE_TEST = 1 << 5; /** Bit-field which indicates the number is from the modem config. */ public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 7441c26a8061..f3a335d93a6c 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import com.android.internal.telephony.SmsRawData; /** @@ -570,17 +569,6 @@ interface ISms { int subId, String callingPkg, String prefixes, in PendingIntent intent); /** - * Get sms inbox messages for the calling financial app. - * - * @param subId the SIM id. - * @param callingPkg the package name of the calling app. - * @param params parameters to filter the sms messages. - * @param callback the callback interface to deliver the result. - */ - void getSmsMessagesForFinancialApp( - int subId, String callingPkg, in Bundle params, in IFinancialSmsCallback callback); - - /** * Check if the destination is a possible premium short code. * * @param destAddress the destination address to test for possible short code diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java index aa1f94f2355a..2096325b09f2 100644 --- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java +++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import java.util.List; @@ -198,12 +197,6 @@ public class ISmsImplBase extends ISms.Stub { } @Override - public void getSmsMessagesForFinancialApp( - int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) { - throw new UnsupportedOperationException(); - } - - @Override public int checkSmsShortCodeDestination( int subid, String callingApk, String destAddress, String countryIso) { throw new UnsupportedOperationException(); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 866e936a1211..4d9057975727 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -302,7 +302,7 @@ interface ITelephony { * operator's MCC (Mobile Country Code). * @see android.telephony.TelephonyManager#getNetworkCountryIso */ - String getNetworkCountryIsoForPhone(int phoneId); + String getNetworkCountryIsoForPhone(int phoneId, String callingPkg); /** * Returns the neighboring cell information of the device. diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java index 730b210f1529..fe1d9d26c7e7 100644 --- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java +++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java @@ -92,5 +92,18 @@ public class BootImageProfileTest implements IDeviceTest { } assertTrue("Did not see framework.jar in " + res, sawFramework); assertTrue("Did not see services.jar in " + res, sawServices); + + + // Test the profile contents contain common methods for core-oj that would normally be AOT + // compiled. + res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file=" + + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"); + boolean sawObjectInit = false; + for (String line : res.split("\n")) { + if (line.contains("Ljava/lang/Object;-><init>()V")) { + sawObjectInit = true; + } + } + assertTrue("Did not see Object.<init> in " + res, sawObjectInit); } } diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh index 614cbb7c9eb6..01522735ec3c 100755 --- a/tests/Codegen/runTest.sh +++ b/tests/Codegen/runTest.sh @@ -13,6 +13,7 @@ else header_and_eval m -j16 codegen_cli && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \ + header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java && \ cd $ANDROID_BUILD_TOP && header_and_eval mmma -j16 frameworks/base/tests/Codegen && \ header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \ diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java new file mode 100644 index 000000000000..2d4125783990 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java @@ -0,0 +1,362 @@ +/* + * 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.codegentest; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseArray; +import android.util.SparseIntArray; + +import com.android.internal.util.AnnotationValidations; +import com.android.internal.util.DataClass; + +import java.util.List; +import java.util.Map; + +/** + * Additional test for various parcelling corner-cases. + */ +@DataClass( + genBuilder = true, + genAidl = false, + genToString = true) +public class ParcelAllTheThingsDataClass implements Parcelable { + + @NonNull String[] mStringArray = null; + @NonNull int[] mIntArray = null; + @NonNull List<String> mStringList = null; + + @NonNull Map<String, SampleWithCustomBuilder> mMap = null; + @NonNull Map<String, String> mStringMap = null; + + @NonNull SparseArray<SampleWithCustomBuilder> mSparseArray = null; + @NonNull SparseIntArray mSparseIntArray = null; + + + + // Code below generated by codegen v1.0.4. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java + + + @DataClass.Generated.Member + /* package-private */ ParcelAllTheThingsDataClass( + @NonNull String[] stringArray, + @NonNull int[] intArray, + @NonNull List<String> stringList, + @NonNull Map<String,SampleWithCustomBuilder> map, + @NonNull Map<String,String> stringMap, + @NonNull SparseArray<SampleWithCustomBuilder> sparseArray, + @NonNull SparseIntArray sparseIntArray) { + this.mStringArray = stringArray; + AnnotationValidations.validate( + NonNull.class, null, mStringArray); + this.mIntArray = intArray; + AnnotationValidations.validate( + NonNull.class, null, mIntArray); + this.mStringList = stringList; + AnnotationValidations.validate( + NonNull.class, null, mStringList); + this.mMap = map; + AnnotationValidations.validate( + NonNull.class, null, mMap); + this.mStringMap = stringMap; + AnnotationValidations.validate( + NonNull.class, null, mStringMap); + this.mSparseArray = sparseArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseArray); + this.mSparseIntArray = sparseIntArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseIntArray); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String[] getStringArray() { + return mStringArray; + } + + @DataClass.Generated.Member + public @NonNull int[] getIntArray() { + return mIntArray; + } + + @DataClass.Generated.Member + public @NonNull List<String> getStringList() { + return mStringList; + } + + @DataClass.Generated.Member + public @NonNull Map<String,SampleWithCustomBuilder> getMap() { + return mMap; + } + + @DataClass.Generated.Member + public @NonNull Map<String,String> getStringMap() { + return mStringMap; + } + + @DataClass.Generated.Member + public @NonNull SparseArray<SampleWithCustomBuilder> getSparseArray() { + return mSparseArray; + } + + @DataClass.Generated.Member + public @NonNull SparseIntArray getSparseIntArray() { + return mSparseIntArray; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "ParcelAllTheThingsDataClass { " + + "stringArray = " + java.util.Arrays.toString(mStringArray) + ", " + + "intArray = " + java.util.Arrays.toString(mIntArray) + ", " + + "stringList = " + mStringList + ", " + + "map = " + mMap + ", " + + "stringMap = " + mStringMap + ", " + + "sparseArray = " + mSparseArray + ", " + + "sparseIntArray = " + mSparseIntArray + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeStringArray(mStringArray); + dest.writeIntArray(mIntArray); + dest.writeStringList(mStringList); + dest.writeMap(mMap); + dest.writeMap(mStringMap); + dest.writeSparseArray(mSparseArray); + dest.writeSparseIntArray(mSparseIntArray); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<ParcelAllTheThingsDataClass> CREATOR + = new Parcelable.Creator<ParcelAllTheThingsDataClass>() { + @Override + public ParcelAllTheThingsDataClass[] newArray(int size) { + return new ParcelAllTheThingsDataClass[size]; + } + + @Override + @SuppressWarnings({"unchecked", "RedundantCast"}) + public ParcelAllTheThingsDataClass createFromParcel(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String[] stringArray = in.createStringArray(); + int[] intArray = in.createIntArray(); + List<String> stringList = new java.util.ArrayList<>(); + in.readStringList(stringList); + Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>(); + in.readMap(map, SampleWithCustomBuilder.class.getClassLoader()); + Map<String,String> stringMap = new java.util.LinkedHashMap<>(); + in.readMap(stringMap, String.class.getClassLoader()); + SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader()); + SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray(); + return new ParcelAllTheThingsDataClass( + stringArray, + intArray, + stringList, + map, + stringMap, + sparseArray, + sparseIntArray); + } + }; + + /** + * A builder for {@link ParcelAllTheThingsDataClass} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static class Builder { + + private @NonNull String[] mStringArray; + private @NonNull int[] mIntArray; + private @NonNull List<String> mStringList; + private @NonNull Map<String,SampleWithCustomBuilder> mMap; + private @NonNull Map<String,String> mStringMap; + private @NonNull SparseArray<SampleWithCustomBuilder> mSparseArray; + private @NonNull SparseIntArray mSparseIntArray; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + @DataClass.Generated.Member + public @NonNull Builder setStringArray(@NonNull String... value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mStringArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setIntArray(@NonNull int... value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mIntArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setStringList(@NonNull List<String> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mStringList = value; + return this; + } + + /** @see #setStringList */ + @DataClass.Generated.Member + public @NonNull Builder addStringList(String value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mStringList == null) setStringList(new java.util.ArrayList<>()); + mStringList.add(value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setMap(@NonNull Map<String,SampleWithCustomBuilder> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mMap = value; + return this; + } + + /** @see #setMap */ + @DataClass.Generated.Member + public @NonNull Builder addMap(String key, SampleWithCustomBuilder value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mMap == null) setMap(new java.util.LinkedHashMap()); + mMap.put(key, value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setStringMap(@NonNull Map<String,String> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; + mStringMap = value; + return this; + } + + /** @see #setStringMap */ + @DataClass.Generated.Member + public @NonNull Builder addStringMap(String key, String value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mStringMap == null) setStringMap(new java.util.LinkedHashMap()); + mStringMap.put(key, value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setSparseArray(@NonNull SparseArray<SampleWithCustomBuilder> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mSparseArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setSparseIntArray(@NonNull SparseIntArray value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; + mSparseIntArray = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public ParcelAllTheThingsDataClass build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x80; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mStringArray = null; + } + if ((mBuilderFieldsSet & 0x2) == 0) { + mIntArray = null; + } + if ((mBuilderFieldsSet & 0x4) == 0) { + mStringList = null; + } + if ((mBuilderFieldsSet & 0x8) == 0) { + mMap = null; + } + if ((mBuilderFieldsSet & 0x10) == 0) { + mStringMap = null; + } + if ((mBuilderFieldsSet & 0x20) == 0) { + mSparseArray = null; + } + if ((mBuilderFieldsSet & 0x40) == 0) { + mSparseIntArray = null; + } + ParcelAllTheThingsDataClass o = new ParcelAllTheThingsDataClass( + mStringArray, + mIntArray, + mStringList, + mMap, + mStringMap, + mSparseArray, + mSparseIntArray); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x80) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1570139502128L, + codegenVersion = "1.0.4", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java", + inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)") + @Deprecated + private void __metadata() {} + +} diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index 66c7d06d6ff4..0631f7ded8ae 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -342,7 +342,7 @@ public final class SampleDataClass implements Parcelable { - // Code below generated by codegen v1.0.3. + // Code below generated by codegen v1.0.4. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -1798,8 +1798,8 @@ public final class SampleDataClass implements Parcelable { } @DataClass.Generated( - time = 1569956013899L, - codegenVersion = "1.0.3", + time = 1570139500112L, + codegenVersion = "1.0.4", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java index 663620743af9..c7a773530963 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java @@ -25,9 +25,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; + import android.net.LinkAddress; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.util.SparseArray; +import android.util.SparseIntArray; import androidx.test.runner.AndroidJUnit4; @@ -36,6 +41,9 @@ import org.junit.runner.RunWith; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** @@ -209,6 +217,32 @@ public class SampleDataClassTest { newBuilder().setDayOfWeek(42).build(); } + @Test + public void testDataStructures_parcelCorrectly() { + SampleWithCustomBuilder otherParcelable = new SampleWithCustomBuilder.Builder().setDelay(3, SECONDS).build(); + + ParcelAllTheThingsDataClass instance = new ParcelAllTheThingsDataClass.Builder() + .setIntArray(40, 41) + .addMap("foo", otherParcelable) + .setSparseArray(new SparseArray<SampleWithCustomBuilder>() {{ + put(45, otherParcelable); + }}) + .setSparseIntArray(new SparseIntArray() {{ + put(48, 49); + }}) + .addStringMap("foo2", "fooValue") + .setStringArray("foo", "bar") + .addStringList("foo") + .build(); + + ParcelAllTheThingsDataClass unparceledInstance = + parcelAndUnparcel(instance, ParcelAllTheThingsDataClass.CREATOR); + + // SparseArray and friends don't implement equals + // so just compare string representations instead + assertEquals(instance.toString(), unparceledInstance.toString()); + } + private static <T extends Parcelable> T parcelAndUnparcel( T original, Parcelable.Creator<T> creator) { Parcel p = Parcel.obtain(); diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java index c6bc8de3bb9e..0f8c663f5d4b 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -17,14 +17,16 @@ package com.android.codegentest; import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; import android.os.SystemClock; import com.android.internal.util.DataClass; import java.util.concurrent.TimeUnit; -@DataClass(genBuilder = true) -public class SampleWithCustomBuilder { +@DataClass(genBuilder = true, genAidl = false, genToString = true) +public class SampleWithCustomBuilder implements Parcelable { long delayAmount = 0; @NonNull @@ -73,8 +75,17 @@ public class SampleWithCustomBuilder { } + private static TimeUnit unparcelDelayUnit(Parcel p) { + return TimeUnit.values()[p.readInt()]; + } + + private void parcelDelayUnit(Parcel p, int flags) { + p.writeInt(delayUnit.ordinal()); + } - // Code below generated by codegen v1.0.3. + + + // Code below generated by codegen v1.0.4. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -112,6 +123,58 @@ public class SampleWithCustomBuilder { return creationTimestamp; } + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "SampleWithCustomBuilder { " + + "delayAmount = " + delayAmount + ", " + + "delayUnit = " + delayUnit + ", " + + "creationTimestamp = " + creationTimestamp + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeLong(delayAmount); + parcelDelayUnit(dest, flags); + dest.writeLong(creationTimestamp); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<SampleWithCustomBuilder> CREATOR + = new Parcelable.Creator<SampleWithCustomBuilder>() { + @Override + public SampleWithCustomBuilder[] newArray(int size) { + return new SampleWithCustomBuilder[size]; + } + + @Override + @SuppressWarnings({"unchecked", "RedundantCast"}) + public SampleWithCustomBuilder createFromParcel(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long _delayAmount = in.readLong(); + TimeUnit _delayUnit = unparcelDelayUnit(in); + long _creationTimestamp = in.readLong(); + return new SampleWithCustomBuilder( + _delayAmount, + _delayUnit, + _creationTimestamp); + } + }; + /** * A builder for {@link SampleWithCustomBuilder} */ @@ -176,10 +239,10 @@ public class SampleWithCustomBuilder { } @DataClass.Generated( - time = 1569956014908L, - codegenVersion = "1.0.3", + time = 1570139501160L, + codegenVersion = "1.0.4", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", - inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/tests/MirrorSurfaceTest/Android.bp b/tests/MirrorSurfaceTest/Android.bp new file mode 100644 index 000000000000..e359c64cc982 --- /dev/null +++ b/tests/MirrorSurfaceTest/Android.bp @@ -0,0 +1,6 @@ +android_test { + name: "MirrorSurfaceTest", + srcs: ["src/**/*.java"], + platform_apis: true, + certificate: "platform", +} diff --git a/tests/MirrorSurfaceTest/AndroidManifest.xml b/tests/MirrorSurfaceTest/AndroidManifest.xml new file mode 100644 index 000000000000..123cd0f26ff3 --- /dev/null +++ b/tests/MirrorSurfaceTest/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.mirrorsurface"> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + + <application android:label="MirrorSurfaceTest"> + <activity android:name=".MirrorSurfaceActivity" + android:label="Mirror Surface" + android:configChanges="orientation|screenSize"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml b/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml new file mode 100644 index 000000000000..73b509f743d1 --- /dev/null +++ b/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="20dp" + android:orientation="horizontal"> + + <Button + android:id="@+id/mirror_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="20dp" + android:text="Mirror" + android:textSize="20dp" /> + + <Button + android:id="@+id/remove_mirror_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="20dp" + android:text="Remove Mirror" + android:textSize="20dp" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:layout_marginTop="10dp" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="20dp" + android:text="SCALE: " /> + + <EditText + android:hint="0.5" + android:id="@+id/scale" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="numberDecimal" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:layout_marginTop="10dp" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="20dp" + android:text="DISPLAY FRAME: " /> + + <EditText + android:hint="0, 0, 20, 20" + android:id="@+id/displayFrame" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="numberDecimal|text"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:layout_marginTop="10dp" + android:orientation="horizontal"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="20dp" + android:text="SOURCE POSITION: " /> + + <TextView + android:id="@+id/sourcePosition" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="numberDecimal|text"/> + </LinearLayout> +</LinearLayout> diff --git a/tests/MirrorSurfaceTest/res/layout/move_view.xml b/tests/MirrorSurfaceTest/res/layout/move_view.xml new file mode 100644 index 000000000000..57077006765e --- /dev/null +++ b/tests/MirrorSurfaceTest/res/layout/move_view.xml @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="20dp" + android:gravity="center"> + + <RelativeLayout + android:id="@+id/arrows" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <ImageButton + android:id="@+id/up_arrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toEndOf="@+id/right_arrow" + android:background="@android:color/holo_green_light" + android:padding="10dp" + android:src="@android:drawable/arrow_up_float" /> + + <ImageButton + android:id="@+id/down_arrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/up_arrow" + android:layout_marginTop="80dp" + android:layout_toEndOf="@+id/right_arrow" + android:background="@android:color/holo_green_light" + android:padding="10dp" + android:src="@android:drawable/arrow_down_float" /> + + <ImageButton + android:id="@+id/right_arrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@+id/up_arrow" + android:layout_alignBottom="@+id/down_arrow" + android:layout_marginTop="55dp" + android:layout_marginEnd="15dp" + android:layout_marginBottom="55dp" + android:background="@android:color/holo_green_light" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:rotation="90" + android:src="@android:drawable/arrow_down_float" /> + + <ImageButton + android:id="@+id/left_arrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignTop="@+id/up_arrow" + android:layout_alignBottom="@+id/down_arrow" + android:layout_marginStart="15dp" + android:layout_marginTop="55dp" + android:layout_marginBottom="55dp" + android:layout_toEndOf="@+id/down_arrow" + android:background="@android:color/holo_green_light" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:rotation="-90" + android:src="@android:drawable/arrow_down_float" /> + </RelativeLayout> + + <RelativeLayout + + android:layout_gravity="center" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <Button + android:id="@+id/zoom_in_button" + android:layout_width="40dp" + android:layout_marginBottom="-8dp" + android:layout_height="40dp" + android:text="+" /> + + <Button + android:layout_below="@+id/zoom_in_button" + android:id="@+id/zoom_out_button" + android:layout_width="40dp" + android:layout_height="40dp" + android:text="-" /> + </RelativeLayout> +</FrameLayout>
\ No newline at end of file diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java new file mode 100644 index 000000000000..b863713df15b --- /dev/null +++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java @@ -0,0 +1,441 @@ +/* + * 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.google.android.test.mirrorsurface; + + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.IWindowManager; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.SurfaceControl; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class MirrorSurfaceActivity extends Activity implements View.OnClickListener, + View.OnLongClickListener, View.OnTouchListener { + private static final int BORDER_SIZE = 10; + private static final int DEFAULT_SCALE = 2; + private static final int DEFAULT_BORDER_COLOR = Color.argb(255, 255, 153, 0); + private static final int MOVE_FRAME_AMOUNT = 20; + + private IWindowManager mIWm; + private WindowManager mWm; + + private SurfaceControl mSurfaceControl = new SurfaceControl(); + private SurfaceControl mBorderSc; + + private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); + private View mOverlayView; + private View mArrowOverlay; + + private Rect mDisplayBounds = new Rect(); + + private EditText mScaleText; + private EditText mDisplayFrameText; + private TextView mSourcePositionText; + + private Rect mTmpRect = new Rect(); + private final Surface mTmpSurface = new Surface(); + + private boolean mHasMirror; + + private Rect mCurrFrame = new Rect(); + private float mCurrScale = DEFAULT_SCALE; + + private final Handler mHandler = new Handler(); + + private MoveMirrorRunnable mMoveMirrorRunnable = new MoveMirrorRunnable(); + private boolean mIsPressedDown = false; + + private int mDisplayId; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_mirror_surface); + mWm = (WindowManager) getSystemService(WINDOW_SERVICE); + mIWm = WindowManagerGlobal.getWindowManagerService(); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + mDisplayBounds.set(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels); + + mScaleText = findViewById(R.id.scale); + mDisplayFrameText = findViewById(R.id.displayFrame); + mSourcePositionText = findViewById(R.id.sourcePosition); + + mCurrFrame.set(0, 0, mDisplayBounds.width() / 2, mDisplayBounds.height() / 2); + mCurrScale = DEFAULT_SCALE; + + mDisplayId = getWindowManager().getDefaultDisplay().getDisplayId(); + updateEditTexts(); + + findViewById(R.id.mirror_button).setOnClickListener(view -> { + if (mArrowOverlay == null) { + createArrowOverlay(); + } + createOrUpdateMirror(); + }); + + findViewById(R.id.remove_mirror_button).setOnClickListener(v -> { + removeMirror(); + removeArrowOverlay(); + }); + + createMirrorOverlay(); + } + + private void updateEditTexts() { + mDisplayFrameText.setText( + String.format("%s, %s, %s, %s", mCurrFrame.left, mCurrFrame.top, mCurrFrame.right, + mCurrFrame.bottom)); + mScaleText.setText(String.valueOf(mCurrScale)); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mOverlayView != null) { + removeMirror(); + mWm.removeView(mOverlayView); + mOverlayView = null; + } + removeArrowOverlay(); + } + + private void createArrowOverlay() { + mArrowOverlay = getLayoutInflater().inflate(R.layout.move_view, null); + WindowManager.LayoutParams arrowParams = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.RGBA_8888); + arrowParams.gravity = Gravity.RIGHT | Gravity.BOTTOM; + mWm.addView(mArrowOverlay, arrowParams); + + View leftArrow = mArrowOverlay.findViewById(R.id.left_arrow); + View topArrow = mArrowOverlay.findViewById(R.id.up_arrow); + View rightArrow = mArrowOverlay.findViewById(R.id.right_arrow); + View bottomArrow = mArrowOverlay.findViewById(R.id.down_arrow); + + leftArrow.setOnClickListener(this); + topArrow.setOnClickListener(this); + rightArrow.setOnClickListener(this); + bottomArrow.setOnClickListener(this); + + leftArrow.setOnLongClickListener(this); + topArrow.setOnLongClickListener(this); + rightArrow.setOnLongClickListener(this); + bottomArrow.setOnLongClickListener(this); + + leftArrow.setOnTouchListener(this); + topArrow.setOnTouchListener(this); + rightArrow.setOnTouchListener(this); + bottomArrow.setOnTouchListener(this); + + mArrowOverlay.findViewById(R.id.zoom_in_button).setOnClickListener(v -> { + if (mCurrScale <= 1) { + mCurrScale *= 2; + } else { + mCurrScale += 0.5; + } + + updateMirror(mCurrFrame, mCurrScale); + }); + mArrowOverlay.findViewById(R.id.zoom_out_button).setOnClickListener(v -> { + if (mCurrScale <= 1) { + mCurrScale /= 2; + } else { + mCurrScale -= 0.5; + } + + updateMirror(mCurrFrame, mCurrScale); + }); + } + + private void removeArrowOverlay() { + if (mArrowOverlay != null) { + mWm.removeView(mArrowOverlay); + mArrowOverlay = null; + } + } + + private void createMirrorOverlay() { + mOverlayView = new LinearLayout(this); + WindowManager.LayoutParams params = new WindowManager.LayoutParams(mDisplayBounds.width(), + mDisplayBounds.height(), + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.RGBA_8888); + params.gravity = Gravity.LEFT | Gravity.TOP; + params.setTitle("Mirror Overlay"); + mOverlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + + mWm.addView(mOverlayView, params); + + } + + private void removeMirror() { + if (mSurfaceControl.isValid()) { + mTransaction.remove(mSurfaceControl).apply(); + } + mHasMirror = false; + } + + private void createOrUpdateMirror() { + if (mHasMirror) { + updateMirror(getDisplayFrame(), getScale()); + } else { + createMirror(getDisplayFrame(), getScale()); + } + + } + + private Rect getDisplayFrame() { + mTmpRect.setEmpty(); + String[] frameVals = mDisplayFrameText.getText().toString().split("\\s*,\\s*"); + if (frameVals.length != 4) { + return mTmpRect; + } + + try { + mTmpRect.set(Integer.parseInt(frameVals[0]), Integer.parseInt(frameVals[1]), + Integer.parseInt(frameVals[2]), Integer.parseInt(frameVals[3])); + } catch (Exception e) { + mTmpRect.setEmpty(); + } + + return mTmpRect; + } + + private float getScale() { + try { + return Float.parseFloat(mScaleText.getText().toString()); + } catch (Exception e) { + return -1; + } + } + + private void createMirror(Rect displayFrame, float scale) { + boolean success = false; + try { + success = mIWm.mirrorDisplay(mDisplayId, mSurfaceControl); + } catch (RemoteException e) { + } + + if (!success) { + return; + } + + if (!mSurfaceControl.isValid()) { + return; + } + + mHasMirror = true; + + mBorderSc = new SurfaceControl.Builder() + .setName("Mirror Border") + .setBufferSize(1, 1) + .setFormat(PixelFormat.TRANSLUCENT) + .build(); + + updateMirror(displayFrame, scale); + + mTransaction + .show(mSurfaceControl) + .reparent(mSurfaceControl, mOverlayView.getViewRootImpl().getSurfaceControl()) + .setLayer(mBorderSc, 1) + .show(mBorderSc) + .reparent(mBorderSc, mSurfaceControl) + .apply(); + } + + private void updateMirror(Rect displayFrame, float scale) { + if (displayFrame.isEmpty()) { + Rect bounds = mDisplayBounds; + int defaultCropW = Math.round(bounds.width() / 2); + int defaultCropH = Math.round(bounds.height() / 2); + displayFrame.set(0, 0, defaultCropW, defaultCropH); + } + + if (scale <= 0) { + scale = DEFAULT_SCALE; + } + + mCurrFrame.set(displayFrame); + mCurrScale = scale; + + int width = (int) Math.ceil(displayFrame.width() / scale); + int height = (int) Math.ceil(displayFrame.height() / scale); + + Rect sourceBounds = getSourceBounds(displayFrame, scale); + + mTransaction.setGeometry(mSurfaceControl, sourceBounds, displayFrame, Surface.ROTATION_0) + .setPosition(mBorderSc, sourceBounds.left, sourceBounds.top) + .setBufferSize(mBorderSc, width, height) + .apply(); + + drawBorder(mBorderSc, width, height, (int) Math.ceil(BORDER_SIZE / scale)); + + mSourcePositionText.setText(sourceBounds.left + ", " + sourceBounds.top); + mDisplayFrameText.setText( + String.format("%s, %s, %s, %s", mCurrFrame.left, mCurrFrame.top, mCurrFrame.right, + mCurrFrame.bottom)); + mScaleText.setText(String.valueOf(mCurrScale)); + } + + private void drawBorder(SurfaceControl borderSc, int width, int height, int borderSize) { + mTmpSurface.copyFrom(borderSc); + + Canvas c = null; + try { + c = mTmpSurface.lockCanvas(null); + } catch (IllegalArgumentException | Surface.OutOfResourcesException e) { + } + if (c == null) { + return; + } + + // Top + c.save(); + c.clipRect(new Rect(0, 0, width, borderSize)); + c.drawColor(DEFAULT_BORDER_COLOR); + c.restore(); + // Left + c.save(); + c.clipRect(new Rect(0, 0, borderSize, height)); + c.drawColor(DEFAULT_BORDER_COLOR); + c.restore(); + // Right + c.save(); + c.clipRect(new Rect(width - borderSize, 0, width, height)); + c.drawColor(DEFAULT_BORDER_COLOR); + c.restore(); + // Bottom + c.save(); + c.clipRect(new Rect(0, height - borderSize, width, height)); + c.drawColor(DEFAULT_BORDER_COLOR); + c.restore(); + + mTmpSurface.unlockCanvasAndPost(c); + } + + @Override + public void onClick(View v) { + Point offset = findOffset(v); + moveMirrorForArrows(offset.x, offset.y); + } + + @Override + public boolean onLongClick(View v) { + mIsPressedDown = true; + Point point = findOffset(v); + mMoveMirrorRunnable.mXOffset = point.x; + mMoveMirrorRunnable.mYOffset = point.y; + mHandler.post(mMoveMirrorRunnable); + return false; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mIsPressedDown = false; + break; + } + return false; + } + + private Point findOffset(View v) { + Point offset = new Point(0, 0); + + switch (v.getId()) { + case R.id.up_arrow: + offset.y = -MOVE_FRAME_AMOUNT; + break; + case R.id.down_arrow: + offset.y = MOVE_FRAME_AMOUNT; + break; + case R.id.right_arrow: + offset.x = -MOVE_FRAME_AMOUNT; + break; + case R.id.left_arrow: + offset.x = MOVE_FRAME_AMOUNT; + break; + } + + return offset; + } + + private void moveMirrorForArrows(int xOffset, int yOffset) { + mCurrFrame.offset(xOffset, yOffset); + + updateMirror(mCurrFrame, mCurrScale); + } + + /** + * Calculates the desired source bounds. This will be the area under from the center of the + * displayFrame, factoring in scale. + */ + private Rect getSourceBounds(Rect displayFrame, float scale) { + int halfWidth = displayFrame.width() / 2; + int halfHeight = displayFrame.height() / 2; + int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale)); + int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale)); + int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale)); + int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale)); + return new Rect(left, top, right, bottom); + } + + class MoveMirrorRunnable implements Runnable { + int mXOffset = 0; + int mYOffset = 0; + + @Override + public void run() { + if (mIsPressedDown) { + moveMirrorForArrows(mXOffset, mYOffset); + mHandler.postDelayed(mMoveMirrorRunnable, 150); + } + } + } +} diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java index b4f6e99d38c2..46e27c1d3d3b 100644 --- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java +++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java @@ -45,6 +45,7 @@ import androidx.test.runner.AndroidJUnit4; import libcore.util.HexEncoding; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -200,6 +201,7 @@ public class InetDiagSocketTest { checkGetConnectionOwnerUid("::1", "::1"); } + @Ignore("Times out on Marlin/Sailfish") /* Verify fix for b/141603906 */ @Test public void testB141603906() throws Exception { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 9e21db76be84..5bfd647f0152 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -258,13 +258,13 @@ public class ConnectivityServiceTest { private static final String TAG = "ConnectivityServiceTest"; private static final int TIMEOUT_MS = 500; - private static final int TEST_LINGER_DELAY_MS = 250; + private static final int TEST_LINGER_DELAY_MS = 300; // Chosen to be less than the linger timeout. This ensures that we can distinguish between a // LOST callback that arrives immediately and a LOST callback that arrives after the linger // timeout. For this, our assertions should run fast enough to leave less than // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are // supposedly fired, and the time we call expectCallback. - private static final int TEST_CALLBACK_TIMEOUT_MS = 200; + private static final int TEST_CALLBACK_TIMEOUT_MS = 250; // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to // complete before callbacks are verified. private static final int TEST_REQUEST_TIMEOUT_MS = 150; @@ -1466,6 +1466,10 @@ public class ConnectivityServiceTest { * received. assertNoCallback may be called at any time. */ private class TestNetworkCallback extends TestableNetworkCallback { + TestNetworkCallback() { + super(TEST_CALLBACK_TIMEOUT_MS); + } + @Override public void assertNoCallback() { // TODO: better support this use case in TestableNetworkCallback diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index 914e475cfe41..865340566019 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -341,7 +341,7 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) { } } - if (Type.contains("Map<")) { + if (FieldClass.endsWith("Map") && FieldInnerType != null) { generateBuilderMethod( name = adderName, defVisibility = visibility, @@ -533,7 +533,7 @@ fun ClassPrinter.generateParcelable() { } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && ParcelMethodsSuffix != "Parcelable") { - !"($Type) " + !"($FieldClass) " } } @@ -541,12 +541,15 @@ fun ClassPrinter.generateParcelable() { when { ParcelMethodsSuffix == "Parcelable" -> methodArgs += "$FieldClass.class.getClassLoader()" + ParcelMethodsSuffix == "SparseArray" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" ParcelMethodsSuffix == "TypedObject" -> methodArgs += "$FieldClass.CREATOR" ParcelMethodsSuffix == "TypedArray" -> methodArgs += "$FieldInnerClass.CREATOR" + ParcelMethodsSuffix == "Map" -> + methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" ParcelMethodsSuffix.startsWith("Parcelable") - || FieldClass == "Map" || (isList || isArray) && FieldInnerType !in PRIMITIVE_TYPES + "String" -> methodArgs += "$FieldInnerClass.class.getClassLoader()" diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 1e3973eaa022..1cc7ef338cc3 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.3" +const val CODEGEN_VERSION = "1.0.4" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index 97f3de2c1221..70ac0bee59b3 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -50,14 +50,19 @@ object ProtoLogTool { command.javaSourceArgs.forEach { path -> val file = File(path) val text = file.readText() - val code = tryParse(text, path) - val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration - .get().nameAsString else "" - val newPath = pack.replace('.', '/') + '/' + file.name - val outSrc = when { - containsProtoLogText(text, command.protoLogClassNameArg) -> + val newPath = path + val outSrc = try { + val code = tryParse(text, path) + if (containsProtoLogText(text, command.protoLogClassNameArg)) { transformer.processClass(text, newPath, code) - else -> text + } else { + text + } + } catch (ex: ParsingException) { + // If we cannot parse this file, skip it (and log why). Compilation will fail + // in a subsequent build step. + println("\n${ex.message}\n") + text } outJar.putNextEntry(ZipEntry(newPath)) outJar.write(outSrc.toByteArray()) @@ -91,11 +96,17 @@ object ProtoLogTool { val file = File(path) val text = file.readText() if (containsProtoLogText(text, command.protoLogClassNameArg)) { - val code = tryParse(text, path) - val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration - .get().nameAsString else "" - val newPath = pack.replace('.', '/') + '/' + file.name - builder.processClass(code, newPath) + try { + val code = tryParse(text, path) + val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration + .get().nameAsString else "" + val newPath = pack.replace('.', '/') + '/' + file.name + builder.processClass(code, newPath) + } catch (ex: ParsingException) { + // If we cannot parse this file, skip it (and log why). Compilation will fail + // in a subsequent build step. + println("\n${ex.message}\n") + } } } val out = FileOutputStream(command.viewerConfigJsonArg) diff --git a/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl new file mode 100644 index 000000000000..b83b594c8cb9 --- /dev/null +++ b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl @@ -0,0 +1,30 @@ +/** + * 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.net.wifi; + +import android.net.wifi.WifiConfiguration; + +/** + * Communicates LOHS status back to the application process. + * + * @hide + */ +oneway interface ILocalOnlyHotspotCallback { + void onHotspotStarted(in WifiConfiguration config); + void onHotspotStopped(); + void onHotspotFailed(int reason); +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index a97a5a5ec593..b7e109463dab 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -26,6 +26,7 @@ import android.net.DhcpInfo; import android.net.Network; import android.net.wifi.IActionListener; import android.net.wifi.IDppCallback; +import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; @@ -138,11 +139,11 @@ interface IWifiManager boolean stopSoftAp(); - int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName); + int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName); void stopLocalOnlyHotspot(); - void startWatchLocalOnlyHotspot(in Messenger messenger, in IBinder binder); + void startWatchLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback); void stopWatchLocalOnlyHotspot(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 00895e846e82..5782f5b1ab31 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -45,10 +45,9 @@ import android.net.wifi.hotspot2.ProvisioningCallback; import android.os.Binder; import android.os.Build; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Looper; -import android.os.Message; -import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.WorkSource; @@ -1127,16 +1126,6 @@ public class WifiManager { private Looper mLooper; private boolean mVerboseLoggingEnabled = false; - /* LocalOnlyHotspot callback message types */ - /** @hide */ - public static final int HOTSPOT_STARTED = 0; - /** @hide */ - public static final int HOTSPOT_STOPPED = 1; - /** @hide */ - public static final int HOTSPOT_FAILED = 2; - /** @hide */ - public static final int HOTSPOT_OBSERVER_REGISTERED = 3; - private final Object mLock = new Object(); // lock guarding access to the following vars @GuardedBy("mLock") private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy; @@ -2730,6 +2719,13 @@ public class WifiManager { } } + private Executor executorForHandler(@Nullable Handler handler) { + if (handler == null) { + return mContext.getMainExecutor(); + } + return new HandlerExecutor(handler); + } + /** * Request a local only hotspot that an application can use to communicate between co-located * devices connected to the created WiFi hotspot. The network created by this method will not @@ -2787,21 +2783,20 @@ public class WifiManager { */ public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler) { + Executor executor = executorForHandler(handler); synchronized (mLock) { - Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); LocalOnlyHotspotCallbackProxy proxy = - new LocalOnlyHotspotCallbackProxy(this, looper, callback); + new LocalOnlyHotspotCallbackProxy(this, executor, callback); try { IWifiManager iWifiManager = getIWifiManager(); if (iWifiManager == null) { throw new RemoteException("Wifi service is not running"); } String packageName = mContext.getOpPackageName(); - int returnCode = iWifiManager.startLocalOnlyHotspot( - proxy.getMessenger(), new Binder(), packageName); + int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName); if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) { // Send message to the proxy to make sure we call back on the correct thread - proxy.notifyFailed(returnCode); + proxy.onHotspotFailed(returnCode); return; } mLOHSCallbackProxy = proxy; @@ -2879,16 +2874,16 @@ public class WifiManager { */ public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler) { + Executor executor = executorForHandler(handler); synchronized (mLock) { - Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); - mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer); + mLOHSObserverProxy = + new LocalOnlyHotspotObserverProxy(this, executor, observer); try { IWifiManager iWifiManager = getIWifiManager(); if (iWifiManager == null) { throw new RemoteException("Wifi service is not running"); } - iWifiManager.startWatchLocalOnlyHotspot( - mLOHSObserverProxy.getMessenger(), new Binder()); + iWifiManager.startWatchLocalOnlyHotspot(mLOHSObserverProxy); mLOHSObserverProxy.registered(); } catch (RemoteException e) { mLOHSObserverProxy = null; @@ -3446,82 +3441,58 @@ public class WifiManager { /** * Callback proxy for LocalOnlyHotspotCallback objects. */ - private static class LocalOnlyHotspotCallbackProxy { - private final Handler mHandler; + private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub { private final WeakReference<WifiManager> mWifiManager; - private final Looper mLooper; - private final Messenger mMessenger; + private final Executor mExecutor; + private final LocalOnlyHotspotCallback mCallback; /** - * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper. All callbacks - * will be delivered on the thread of the specified looper. + * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor. All + * callbacks will run using the given executor. * * @param manager WifiManager - * @param looper Looper for delivering callbacks + * @param executor Executor for delivering callbacks. * @param callback LocalOnlyHotspotCallback to notify the calling application. */ - LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper, - final LocalOnlyHotspotCallback callback) { + LocalOnlyHotspotCallbackProxy(WifiManager manager, Executor executor, + LocalOnlyHotspotCallback callback) { mWifiManager = new WeakReference<>(manager); - mLooper = looper; - - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: " - + msg.what + " msg: " + msg); - - WifiManager manager = mWifiManager.get(); - if (manager == null) { - Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC"); - return; - } + mExecutor = executor; + mCallback = callback; + } - switch (msg.what) { - case HOTSPOT_STARTED: - WifiConfiguration config = (WifiConfiguration) msg.obj; - if (config == null) { - Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null."); - callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC); - return; - } - callback.onStarted(manager.new LocalOnlyHotspotReservation(config)); - break; - case HOTSPOT_STOPPED: - Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped"); - callback.onStopped(); - break; - case HOTSPOT_FAILED: - int reasonCode = msg.arg1; - Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: " - + reasonCode); - callback.onFailed(reasonCode); - Log.w(TAG, "done with the callback..."); - break; - default: - Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message. type: " - + msg.what); - } - } - }; - mMessenger = new Messenger(mHandler); + @Override + public void onHotspotStarted(WifiConfiguration config) { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + if (config == null) { + Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null."); + onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC); + return; + } + final LocalOnlyHotspotReservation reservation = + manager.new LocalOnlyHotspotReservation(config); + mExecutor.execute(() -> mCallback.onStarted(reservation)); } - public Messenger getMessenger() { - return mMessenger; + @Override + public void onHotspotStopped() { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped"); + mExecutor.execute(() -> mCallback.onStopped()); } - /** - * Helper method allowing the the incoming application call to move the onFailed callback - * over to the desired callback thread. - * - * @param reason int representing the error type - */ - public void notifyFailed(int reason) throws RemoteException { - Message msg = Message.obtain(); - msg.what = HOTSPOT_FAILED; - msg.arg1 = reason; - mMessenger.send(msg); + @Override + public void onHotspotFailed(int reason) { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start. reason: " + + reason); + mExecutor.execute(() -> mCallback.onFailed(reason)); } } @@ -3589,69 +3560,57 @@ public class WifiManager { /** * Callback proxy for LocalOnlyHotspotObserver objects. */ - private static class LocalOnlyHotspotObserverProxy { - private final Handler mHandler; + private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub { private final WeakReference<WifiManager> mWifiManager; - private final Looper mLooper; - private final Messenger mMessenger; + private final Executor mExecutor; + private final LocalOnlyHotspotObserver mObserver; /** * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper. * All callbacks will be delivered on the thread of the specified looper. * * @param manager WifiManager - * @param looper Looper for delivering callbacks + * @param executor Executor for delivering callbacks * @param observer LocalOnlyHotspotObserver to notify the calling application. */ - LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper, + LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer) { mWifiManager = new WeakReference<>(manager); - mLooper = looper; - - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: " - + msg.what + " msg: " + msg); - - WifiManager manager = mWifiManager.get(); - if (manager == null) { - Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC"); - return; - } + mExecutor = executor; + mObserver = observer; + } - switch (msg.what) { - case HOTSPOT_OBSERVER_REGISTERED: - observer.onRegistered(manager.new LocalOnlyHotspotSubscription()); - break; - case HOTSPOT_STARTED: - WifiConfiguration config = (WifiConfiguration) msg.obj; - if (config == null) { - Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null."); - return; - } - observer.onStarted(config); - break; - case HOTSPOT_STOPPED: - observer.onStopped(); - break; - default: - Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message. type: " - + msg.what); - } - } - }; - mMessenger = new Messenger(mHandler); + public void registered() throws RemoteException { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + mExecutor.execute(() -> + mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription())); + } + + @Override + public void onHotspotStarted(WifiConfiguration config) { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + if (config == null) { + Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null."); + return; + } + mExecutor.execute(() -> mObserver.onStarted(config)); } - public Messenger getMessenger() { - return mMessenger; + @Override + public void onHotspotStopped() { + WifiManager manager = mWifiManager.get(); + if (manager == null) return; + + mExecutor.execute(() -> mObserver.onStopped()); } - public void registered() throws RemoteException { - Message msg = Message.obtain(); - msg.what = HOTSPOT_OBSERVER_REGISTERED; - mMessenger.send(msg); + @Override + public void onHotspotFailed(int reason) { + // do nothing } } diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index 2e82f4e8c23b..4ca2a16252d6 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -23,6 +23,7 @@ import android.net.DhcpInfo; import android.net.Network; import android.net.wifi.IActionListener; import android.net.wifi.IDppCallback; +import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiUsabilityStatsListener; import android.net.wifi.ISoftApCallback; @@ -205,11 +206,6 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - /** @removed */ - public void setCountryCode(String country) { - throw new UnsupportedOperationException(); - } - @Override public String getCountryCode() { throw new UnsupportedOperationException(); @@ -285,22 +281,34 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** @deprecated replaced by {@link #startLocalOnlyHotspot(ILocalOnlyHotspotCallback, String)} */ + @Deprecated public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) { throw new UnsupportedOperationException(); } @Override - public void stopLocalOnlyHotspot() { + public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName) { throw new UnsupportedOperationException(); } @Override + public void stopLocalOnlyHotspot() { + throw new UnsupportedOperationException(); + } + + /** @deprecated replaced by {@link #startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback)} */ + @Deprecated public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) { throw new UnsupportedOperationException(); } @Override + public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) { + throw new UnsupportedOperationException(); + } + + @Override public void stopWatchLocalOnlyHotspot() { throw new UnsupportedOperationException(); } @@ -325,11 +333,6 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - /** @removed */ - public Messenger getWifiServiceMessenger(String packageName) { - throw new UnsupportedOperationException(); - } - @Override public void enableTdls(String remoteIPAddress, boolean enable) { throw new UnsupportedOperationException(); diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 7e7f00281529..885139b99b5f 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -16,9 +16,6 @@ package android.net.wifi; -import static android.net.wifi.WifiManager.HOTSPOT_FAILED; -import static android.net.wifi.WifiManager.HOTSPOT_STARTED; -import static android.net.wifi.WifiManager.HOTSPOT_STOPPED; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL; @@ -68,8 +65,6 @@ import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; import android.os.RemoteException; import android.os.test.TestLooper; @@ -117,8 +112,6 @@ public class WifiManagerTest { private Handler mHandler; private TestLooper mLooper; private WifiManager mWifiManager; - private Messenger mWifiServiceMessenger; - final ArgumentCaptor<Messenger> mMessengerCaptor = ArgumentCaptor.forClass(Messenger.class); @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -128,7 +121,6 @@ public class WifiManagerTest { when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME); - mWifiServiceMessenger = new Messenger(mHandler); mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper()); verify(mWifiService).getVerboseLoggingLevel(); } @@ -178,7 +170,7 @@ public class WifiManagerTest { @Test public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); @@ -196,7 +188,7 @@ public class WifiManagerTest { public void testLocalOnlyHotspotReservationCallsStopProperlyInTryWithResources() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); @@ -357,7 +349,7 @@ public class WifiManagerTest { mWifiManager.startLocalOnlyHotspot(callback, mHandler); verify(mWifiService) - .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString()); + .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString()); } /** @@ -368,7 +360,7 @@ public class WifiManagerTest { public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); doThrow(new SecurityException()).when(mWifiService) - .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString()); + .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString()); mWifiManager.startLocalOnlyHotspot(callback, mHandler); } @@ -380,7 +372,7 @@ public class WifiManagerTest { public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); doThrow(new IllegalStateException()).when(mWifiService) - .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString()); + .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString()); mWifiManager.startLocalOnlyHotspot(callback, mHandler); } @@ -390,12 +382,13 @@ public class WifiManagerTest { @Test public void testCorrectLooperIsUsedForHandler() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mLooper.dispatchAll(); assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); verify(mContext, never()).getMainLooper(); + verify(mContext, never()).getMainExecutor(); } /** @@ -406,15 +399,15 @@ public class WifiManagerTest { public void testMainLooperIsUsedWhenHandlerNotProvided() throws Exception { // record thread from looper.getThread and check ids. TestLooper altLooper = new TestLooper(); - when(mContext.getMainLooper()).thenReturn(altLooper.getLooper()); + when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor()); TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE); mWifiManager.startLocalOnlyHotspot(callback, null); altLooper.dispatchAll(); assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason); assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId); - verify(mContext).getMainLooper(); + verify(mContext).getMainExecutor(); } /** @@ -426,18 +419,17 @@ public class WifiManagerTest { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); TestLooper callbackLooper = new TestLooper(); Handler callbackHandler = new Handler(callbackLooper.getLooper()); - when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString())) + .thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); callbackLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(callback.mOnStartedCalled); assertEquals(null, callback.mRes); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STARTED; - msg.obj = mApConfig; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStarted(mApConfig); mLooper.dispatchAll(); callbackLooper.dispatchAll(); assertTrue(callback.mOnStartedCalled); @@ -453,17 +445,17 @@ public class WifiManagerTest { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); TestLooper callbackLooper = new TestLooper(); Handler callbackHandler = new Handler(callbackLooper.getLooper()); - when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString())) + .thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); callbackLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(callback.mOnStartedCalled); assertEquals(null, callback.mRes); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STARTED; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStarted(null); mLooper.dispatchAll(); callbackLooper.dispatchAll(); assertFalse(callback.mOnStartedCalled); @@ -478,16 +470,16 @@ public class WifiManagerTest { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); TestLooper callbackLooper = new TestLooper(); Handler callbackHandler = new Handler(callbackLooper.getLooper()); - when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString())) + .thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); callbackLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(callback.mOnStoppedCalled); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STOPPED; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStopped(); mLooper.dispatchAll(); callbackLooper.dispatchAll(); assertTrue(callback.mOnStoppedCalled); @@ -501,17 +493,16 @@ public class WifiManagerTest { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); TestLooper callbackLooper = new TestLooper(); Handler callbackHandler = new Handler(callbackLooper.getLooper()); - when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString())) + .thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, callbackHandler); callbackLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(ERROR_NOT_SET, callback.mFailureReason); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_FAILED; - msg.arg1 = ERROR_NO_CHANNEL; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotFailed(ERROR_NO_CHANNEL); mLooper.dispatchAll(); callbackLooper.dispatchAll(); assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason); @@ -523,7 +514,7 @@ public class WifiManagerTest { @Test public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mLooper.dispatchAll(); @@ -539,7 +530,7 @@ public class WifiManagerTest { @Test public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(ERROR_TETHERING_DISALLOWED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mLooper.dispatchAll(); @@ -557,7 +548,7 @@ public class WifiManagerTest { public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); doThrow(new SecurityException()).when(mWifiService) - .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString()); + .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString()); try { mWifiManager.startLocalOnlyHotspot(callback, mHandler); } catch (SecurityException e) { @@ -577,7 +568,7 @@ public class WifiManagerTest { @Test public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mLooper.dispatchAll(); @@ -593,7 +584,7 @@ public class WifiManagerTest { @Test public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mWifiManager.cancelLocalOnlyHotspotRequest(); @@ -615,7 +606,7 @@ public class WifiManagerTest { @Test public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(REQUEST_REGISTERED); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mWifiManager.cancelLocalOnlyHotspotRequest(); @@ -634,7 +625,7 @@ public class WifiManagerTest { @Test public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception { TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(); - when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), + when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE); mWifiManager.startLocalOnlyHotspot(callback, mHandler); mLooper.dispatchAll(); @@ -654,7 +645,7 @@ public class WifiManagerTest { TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); mWifiManager.watchLocalOnlyHotspot(observer, mHandler); - verify(mWifiService).startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class)); } /** @@ -665,7 +656,7 @@ public class WifiManagerTest { public void testStartWatchLocalOnlyHotspotThrowsSecurityException() throws Exception { TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); doThrow(new SecurityException()).when(mWifiService) - .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class)); mWifiManager.watchLocalOnlyHotspot(observer, mHandler); } @@ -677,7 +668,7 @@ public class WifiManagerTest { public void testStartWatchLocalOnlyHotspotThrowsIllegalStateException() throws Exception { TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); doThrow(new IllegalStateException()).when(mWifiService) - .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)); + .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class)); mWifiManager.watchLocalOnlyHotspot(observer, mHandler); } @@ -822,6 +813,7 @@ public class WifiManagerTest { verify(mWifiService).registerSoftApCallback(any(IBinder.class), any(ISoftApCallback.Stub.class), anyInt()); verify(mContext, never()).getMainLooper(); + verify(mContext, never()).getMainExecutor(); } /** @@ -834,6 +826,7 @@ public class WifiManagerTest { mLooper.dispatchAll(); assertTrue(observer.mOnRegistered); verify(mContext, never()).getMainLooper(); + verify(mContext, never()).getMainExecutor(); } /** @@ -844,13 +837,13 @@ public class WifiManagerTest { public void testMainLooperIsUsedWhenHandlerNotProvidedForObserver() throws Exception { // record thread from looper.getThread and check ids. TestLooper altLooper = new TestLooper(); - when(mContext.getMainLooper()).thenReturn(altLooper.getLooper()); + when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor()); TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver(); mWifiManager.watchLocalOnlyHotspot(observer, null); altLooper.dispatchAll(); assertTrue(observer.mOnRegistered); assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId); - verify(mContext).getMainLooper(); + verify(mContext).getMainExecutor(); } /** @@ -865,8 +858,7 @@ public class WifiManagerTest { assertFalse(observer.mOnRegistered); assertEquals(null, observer.mSub); mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); - verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class)); + verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class)); // now trigger the callback observerLooper.dispatchAll(); mLooper.dispatchAll(); @@ -884,16 +876,14 @@ public class WifiManagerTest { TestLooper observerLooper = new TestLooper(); Handler observerHandler = new Handler(observerLooper.getLooper()); mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); - verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class)); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture()); observerLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(observer.mOnStartedCalled); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STARTED; - msg.obj = mApConfig; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStarted(mApConfig); mLooper.dispatchAll(); observerLooper.dispatchAll(); assertTrue(observer.mOnStartedCalled); @@ -910,15 +900,14 @@ public class WifiManagerTest { TestLooper observerLooper = new TestLooper(); Handler observerHandler = new Handler(observerLooper.getLooper()); mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); - verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class)); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture()); observerLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(observer.mOnStartedCalled); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STARTED; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStarted(null); mLooper.dispatchAll(); observerLooper.dispatchAll(); assertFalse(observer.mOnStartedCalled); @@ -936,15 +925,14 @@ public class WifiManagerTest { TestLooper observerLooper = new TestLooper(); Handler observerHandler = new Handler(observerLooper.getLooper()); mWifiManager.watchLocalOnlyHotspot(observer, observerHandler); - verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(), - any(IBinder.class)); + ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback = + ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class); + verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture()); observerLooper.dispatchAll(); mLooper.dispatchAll(); assertFalse(observer.mOnStoppedCalled); // now trigger the callback - Message msg = new Message(); - msg.what = HOTSPOT_STOPPED; - mMessengerCaptor.getValue().send(msg); + internalCallback.getValue().onHotspotStopped(); mLooper.dispatchAll(); observerLooper.dispatchAll(); assertTrue(observer.mOnStoppedCalled); @@ -1173,6 +1161,7 @@ i * Verify that a call to cancel WPS immediately returns a failure. Handler altHandler = new Handler(altLooper.getLooper()); mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, altHandler); verify(mContext, never()).getMainLooper(); + verify(mContext, never()).getMainExecutor(); verify(mWifiService).registerTrafficStateCallback( any(IBinder.class), callbackCaptor.capture(), anyInt()); |