summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp15
-rw-r--r--api/system-current.txt15
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h3
-rw-r--r--cmds/statsd/src/StatsService.cpp7
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/atom_field_options.proto14
-rw-r--r--cmds/statsd/src/atoms.proto306
-rw-r--r--cmds/statsd/src/hash.cpp12
-rw-r--r--cmds/statsd/src/main.cpp35
-rw-r--r--cmds/statsd/src/stats_log.proto1
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java18
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java4
-rw-r--r--core/java/android/content/Intent.java6
-rw-r--r--core/java/android/content/pm/ActivityInfo.java8
-rw-r--r--core/java/android/content/pm/PackageParser.java12
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java2
-rw-r--r--core/java/android/hardware/location/ContextHubClient.java2
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java24
-rw-r--r--core/java/android/os/DumpstateOptions.java57
-rw-r--r--core/java/android/os/GraphicsEnvironment.java62
-rw-r--r--core/java/android/os/Message.java10
-rw-r--r--core/java/android/permission/PermissionManager.java55
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/service/textclassifier/TextClassifierService.java4
-rw-r--r--core/java/android/text/style/TextAppearanceSpan.java29
-rw-r--r--core/java/android/view/DisplayCutout.java34
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/com/android/internal/os/LooperStats.java28
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java1
-rw-r--r--core/java/com/android/server/SystemConfig.java8
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp5
-rw-r--r--core/proto/android/internal/powerprofile.proto26
-rw-r--r--core/proto/android/providers/settings/global.proto3
-rw-r--r--core/proto/android/stats/enums.proto (renamed from proto/src/stats_enums.proto)3
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/coretests/src/android/view/DisplayCutoutTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java68
-rw-r--r--graphics/java/android/graphics/ColorSpace.java4
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java3
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java1
-rw-r--r--keystore/OWNERS4
-rw-r--r--media/java/android/media/ExifInterface.java6
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java11
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java1
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt13
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/Painting.kt35
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt22
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml11
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java149
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java8
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto15
-rw-r--r--services/core/Android.bp2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java20
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java65
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java65
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java4
-rw-r--r--services/core/java/com/android/server/am/LaunchParamsController.java66
-rw-r--r--services/core/java/com/android/server/am/TaskLaunchParamsModifier.java862
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java5
-rw-r--r--services/core/java/com/android/server/connectivity/ProxyTracker.java68
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientBroker.java7
-rw-r--r--services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java8
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java4
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java20
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java2
-rw-r--r--services/net/java/android/net/ip/IpNeighborMonitor.java1
-rw-r--r--services/net/java/android/net/netlink/NetlinkSocket.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java144
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java1189
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java58
-rw-r--r--telecomm/java/android/telecom/Call.java14
-rw-r--r--telephony/java/android/provider/Telephony.java1
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationState.java44
-rw-r--r--telephony/java/android/telephony/ServiceState.java148
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java50
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java3
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java57
-rw-r--r--tests/NetworkSecurityConfigTest/Android.mk1
-rw-r--r--tools/aapt2/cmd/Convert.cpp22
-rw-r--r--tools/stats_log_api_gen/Collation.cpp4
-rw-r--r--tools/stats_log_api_gen/test.proto24
104 files changed, 3249 insertions, 1200 deletions
diff --git a/Android.bp b/Android.bp
index 47d06fa02ac8..f9b60e67e659 100644
--- a/Android.bp
+++ b/Android.bp
@@ -614,6 +614,7 @@ java_defaults {
":netd_aidl",
":vold_aidl",
":installd_aidl",
+ ":dumpstate_aidl",
"lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
"lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
@@ -660,6 +661,7 @@ java_defaults {
include_dirs: [
"system/update_engine/binder_bindings",
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"frameworks/av/camera/aidl",
"frameworks/av/media/libaudioclient/aidl",
"frameworks/native/aidl/gui",
@@ -682,9 +684,6 @@ java_defaults {
no_framework_libs: true,
libs: [
- "conscrypt",
- "okhttp",
- "bouncycastle",
"ext",
],
@@ -836,7 +835,6 @@ java_library_host {
"cmds/statsd/src/**/*.proto",
"core/proto/**/*.proto",
"libs/incident/proto/**/*.proto",
- "proto/src/stats_enums.proto",
],
proto: {
include_dirs: ["external/protobuf/src"],
@@ -874,7 +872,6 @@ java_library {
srcs: [
"core/proto/**/*.proto",
"libs/incident/proto/android/os/**/*.proto",
- "proto/src/stats_enums.proto",
],
// Protos have lots of MissingOverride and similar.
errorprone: {
@@ -900,7 +897,6 @@ cc_library {
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- "proto/src/stats_enums.proto",
],
target: {
@@ -1097,14 +1093,13 @@ framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xm
"-federationapi SupportLib $(location current/support-api.txt) "
framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+ "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
"-overview $(location core/java/overview.html) " +
// Federate Support Library references against local API file.
"-federate SupportLib https://developer.android.com " +
"-federationapi SupportLib $(location current/support-api.txt) "
framework_docs_only_libs = [
- "conscrypt",
- "bouncycastle",
"voip-common",
"android.test.mock",
"android-support-annotations",
@@ -1184,7 +1179,8 @@ stubs_defaults {
doc_defaults {
name: "framework-docs-default",
- libs: framework_docs_only_libs,
+ libs: framework_docs_only_libs +
+ ["stub-annotations"],
html_dirs: [
"docs/html",
],
@@ -1581,7 +1577,6 @@ filegroup {
"core/java/org/apache/http/params/CoreConnectionPNames.java",
"core/java/org/apache/http/params/HttpConnectionParams.java",
"core/java/org/apache/http/params/HttpParams.java",
- "core/java/android/net/http/HttpResponseCache.java",
"core/java/android/net/http/SslCertificate.java",
"core/java/android/net/http/SslError.java",
"core/java/com/android/internal/util/HexDump.java",
diff --git a/api/system-current.txt b/api/system-current.txt
index 2188ec17bed4..83a789ad0294 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1281,14 +1281,6 @@ package android.content.pm.permission {
}
-package android.graphics.drawable {
-
- public final class Icon implements android.os.Parcelable {
- method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
- }
-
-}
-
package android.hardware {
public final class Sensor {
@@ -4203,8 +4195,8 @@ package android.permission {
}
public static final class PermissionManager.SplitPermissionInfo {
- method public java.lang.String[] getNewPermissions();
- method public java.lang.String getRootPermission();
+ method public java.util.List<java.lang.String> getNewPermissions();
+ method public java.lang.String getSplitPermission();
method public int getTargetSdk();
}
@@ -5289,6 +5281,7 @@ package android.telephony {
method public int getRejectCause();
method public int getTransportType();
method public boolean isEmergencyEnabled();
+ method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
field public static final int DOMAIN_CS = 1; // 0x1
@@ -5376,6 +5369,8 @@ package android.telephony {
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+ field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
}
public final class SubscriptionPlan implements android.os.Parcelable {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 4091d951ba06..6a9e8a1bf688 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -39,7 +39,8 @@ enum DumpReportReason {
GET_DATA_CALLED = 4,
ADB_DUMP = 5,
CONFIG_RESET = 6,
- STATSCOMPANION_DIED = 7
+ STATSCOMPANION_DIED = 7,
+ TERMINATION_SIGNAL_RECEIVED = 8
};
class StatsLogProcessor : public ConfigListener {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8da2d447a163..fb6f8c8d4590 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -867,6 +867,13 @@ void StatsService::Startup() {
mConfigManager->Startup();
}
+void StatsService::Terminate() {
+ ALOGI("StatsService::Terminating");
+ if (mProcessor != nullptr) {
+ mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED);
+ }
+}
+
void StatsService::OnLogEvent(LogEvent* event) {
mProcessor->OnLogEvent(event);
if (mShellSubscriber != nullptr) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 1f1d782af235..cbf34292c1d4 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -84,6 +84,11 @@ public:
void Startup();
/**
+ * Called when terminiation signal received.
+ */
+ void Terminate();
+
+ /**
* Called by LogReader when there's a log event to process.
*/
virtual void OnLogEvent(LogEvent* event);
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index a2a03b14c073..453bf7e126cd 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -36,8 +36,8 @@ enum StateField {
// exclusive state field, and any number of primary key fields.
// For example,
// message UidProcessStateChanged {
-// optional int32 uid = 1 [(stateFieldOption).option = PRIMARY];
-// optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE];
+// optional int32 uid = 1 [(state_field_option).option = PRIMARY];
+// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
// }
// Each of this UidProcessStateChanged atom represents a state change for a specific uid.
// A new state automatically overrides the previous state.
@@ -46,16 +46,16 @@ enum StateField {
// the primary key.
// For example:
// message ThreadStateChanged {
-// optional int32 pid = 1 [(stateFieldOption).option = PRIMARY];
-// optional int32 tid = 2 [(stateFieldOption).option = PRIMARY];
-// optional int32 state = 3 [(stateFieldOption).option = EXCLUSIVE];
+// optional int32 pid = 1 [(state_field_option).option = PRIMARY];
+// optional int32 tid = 2 [(state_field_option).option = PRIMARY];
+// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE];
// }
//
// Sometimes, there is no primary key field, when the state is GLOBAL.
// For example,
//
// message ScreenStateChanged {
-// optional android.view.DisplayStateEnum state = 1 [(stateFieldOption).option = EXCLUSIVE];
+// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
// }
//
// Only fields of primary types can be annotated. AttributionNode cannot be primary keys (and they
@@ -66,7 +66,7 @@ message StateAtomFieldOption {
extend google.protobuf.FieldOptions {
// Flags to decorate an atom that presents a state change.
- optional StateAtomFieldOption stateFieldOption = 50000;
+ optional StateAtomFieldOption state_field_option = 50000;
// Flags to decorate the uid fields in an atom.
optional bool is_uid = 50001 [default = false];
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8eee9e6af237..957a9b434d05 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -26,12 +26,11 @@ import "frameworks/base/core/proto/android/app/job/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/enums.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/service/procstats_enum.proto";
+import "frameworks/base/core/proto/android/stats/enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/proto/src/stats_enums.proto";
-import "frameworks/base/core/proto/android/service/procstats.proto";
-import "frameworks/base/core/proto/android/internal/powerprofile.proto";
/**
* The master atom class. This message defines all of the available
@@ -129,8 +128,6 @@ message Atom {
AppCrashOccurred app_crash_occurred = 78;
ANROccurred anr_occurred = 79;
WTFOccurred wtf_occurred = 80;
- PhoneServiceStateChanged phone_service_state_changed = 94;
- PhoneStateChanged phone_state_changed = 95;
LowMemReported low_mem_reported = 81;
GenericAtom generic_atom = 82;
KeyValuePairsAtom key_value_pairs_atom = 83;
@@ -144,6 +141,8 @@ message Atom {
BatteryHealthSnapshot battery_health_snapshot = 91;
SlowIo slow_io = 92;
BatteryCausedShutdown battery_caused_shutdown = 93;
+ PhoneServiceStateChanged phone_service_state_changed = 94;
+ PhoneStateChanged phone_state_changed = 95;
}
// Pulled events will start at field 10000.
@@ -275,7 +274,7 @@ message ThermalThrottlingStateChanged {
*/
message ScreenStateChanged {
// New screen state, from frameworks/base/core/proto/android/view/enums.proto.
- optional android.view.DisplayStateEnum state = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -286,10 +285,10 @@ message ScreenStateChanged {
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message UidProcessStateChanged {
- optional int32 uid = 1 [(stateFieldOption).option = PRIMARY, (is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
// The state, from frameworks/base/core/proto/android/app/enums.proto.
- optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE];
+ optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -321,7 +320,7 @@ message ActivityManagerSleepStateChanged {
ASLEEP = 1;
AWAKE = 2;
}
- optional State state = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional State state = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -340,7 +339,7 @@ message MemoryFactorStateChanged {
CRITICAL = 4; // critical memory.
}
- optional State factor = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional State factor = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -1941,7 +1940,7 @@ message LmkKillOccurred {
*/
message AppDied {
// timestamp(elapsedRealtime) of record creation
- optional uint64 timestamp_millis = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -1952,7 +1951,7 @@ message GenericAtom {
optional int32 uid = 1 [(is_uid) = true];
// An event_id indicates the type of event.
- optional android.os.statsd.EventType event_id = 2;
+ optional android.stats.EventType event_id = 2;
}
/**
@@ -2691,11 +2690,288 @@ message NumFingerprints {
optional int32 num_fingerprints = 2;
}
+message AggStats {
+ optional int64 min = 1;
+
+ optional int64 average = 2;
+
+ optional int64 max = 3;
+}
+
+message ProcessStatsStateProto {
+ optional android.service.procstats.ScreenState screen_state = 1;
+
+ optional android.service.procstats.MemoryState memory_state = 2;
+
+ // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+ // and not frameworks/base/core/java/android/app/ActivityManager.java
+ optional android.service.procstats.ProcessState process_state = 3;
+
+ // Millisecond uptime duration spent in this state
+ optional int64 duration_ms = 4;
+
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_ms = 9;
+
+ // # of samples taken
+ optional int32 sample_size = 5;
+
+ // PSS is memory reserved for this process
+ optional AggStats pss = 6;
+
+ // USS is memory shared between processes, divided evenly for accounting
+ optional AggStats uss = 7;
+
+ // RSS is memory resident for this process
+ optional AggStats rss = 8;
+}
+
+// Next Tag: 7
+message ProcessStatsProto {
+ // Name of process.
+ optional string process = 1;
+
+ // Uid of the process.
+ optional int32 uid = 2;
+
+ // Information about how often kills occurred
+ message Kill {
+ // Count of excessive CPU kills
+ optional int32 cpu = 1;
+
+ // Count of kills when cached
+ optional int32 cached = 2;
+
+ // PSS stats during cached kill
+ optional AggStats cached_pss = 3;
+ }
+ optional Kill kill = 3;
+
+ // Time and memory spent in various states.
+ repeated ProcessStatsStateProto states = 5;
+
+ // Total time process has been running... screen_state, memory_state, and process_state
+ // will not be set.
+ optional ProcessStatsStateProto total_running_state = 6;
+}
+
+message PackageServiceOperationStatsProto {
+ // Operate enum: Started, Foreground, Bound, Executing
+ optional android.service.procstats.ServiceOperationState operation = 1;
+
+ // Number of times the service was in this operation.
+ optional int32 count = 2;
+
+ // Information about a state the service can be in.
+ message StateStats {
+ // Screen state enum.
+ optional android.service.procstats.ScreenState screen_state = 1;
+ // Memory state enum.
+ optional android.service.procstats.MemoryState memory_state = 2;
+
+ // duration in milliseconds.
+ optional int64 duration_ms = 3;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_ms = 4;
+ }
+ repeated StateStats state_stats = 3;
+}
+
+message PackageServiceStatsProto {
+ // Name of service component.
+ optional string service_name = 1;
+
+ // The operation stats.
+ // The package_name, package_uid, package_version, service_name will not be set to save space.
+ repeated PackageServiceOperationStatsProto operation_stats = 2;
+}
+
+message PackageAssociationSourceProcessStatsProto {
+ // Uid of the process.
+ optional int32 process_uid = 1;
+ // Process name.
+ optional string process_name = 2;
+
+ // Total count of the times this association appeared.
+ optional int32 total_count = 3;
+
+ // Millisecond uptime total duration this association was around.
+ optional int64 total_duration_ms = 4;
+
+ // Total count of the times this association became actively impacting its target process.
+ optional int32 active_count = 5;
+
+ // Information on one source in this association.
+ message StateStats {
+ // Process state enum.
+ optional android.service.procstats.ProcessState process_state = 1;
+ // Millisecond uptime duration spent in this state
+ optional int64 duration_ms = 2;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_ms = 3;
+ }
+ repeated StateStats active_state_stats = 6;
+}
+
+message PackageAssociationProcessStatsProto {
+ // Name of the target component.
+ optional string component_name = 1;
+ // Information on one source in this association.
+ repeated PackageAssociationSourceProcessStatsProto sources = 2;
+}
+
+
+message ProcessStatsPackageProto {
+ // Name of package.
+ optional string package = 1;
+
+ // Uid of the package.
+ optional int32 uid = 2;
+
+ // Version of the package.
+ optional int64 version = 3;
+
+ // Stats for each process running with the package loaded in to it.
+ repeated ProcessStatsProto process_stats = 4;
+
+ // Stats for each of the package's services.
+ repeated PackageServiceStatsProto service_stats = 5;
+
+ // Stats for each association with the package.
+ repeated PackageAssociationProcessStatsProto association_stats = 6;
+}
+
+message ProcessStatsSectionProto {
+ // Elapsed realtime at start of report.
+ optional int64 start_realtime_ms = 1;
+
+ // Elapsed realtime at end of report.
+ optional int64 end_realtime_ms = 2;
+
+ // CPU uptime at start of report.
+ optional int64 start_uptime_ms = 3;
+
+ // CPU uptime at end of report.
+ optional int64 end_uptime_ms = 4;
+
+ // System runtime library. e.g. "libdvm.so", "libart.so".
+ optional string runtime = 5;
+
+ // whether kernel reports swapped pss.
+ optional bool has_swapped_pss = 6;
+
+ // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
+ enum Status {
+ STATUS_UNKNOWN = 0;
+ STATUS_COMPLETE = 1;
+ STATUS_PARTIAL = 2;
+ STATUS_SHUTDOWN = 3;
+ STATUS_SYSPROPS = 4;
+ }
+ repeated Status status = 7;
+
+ // Stats for each process.
+ repeated ProcessStatsProto process_stats = 8;
+
+ // Stats for each package.
+ repeated ProcessStatsPackageProto package_stats = 9;
+}
+
/**
* Pulled from ProcessStatsService.java
*/
message ProcStats {
- optional android.service.procstats.ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
+message PowerProfileProto {
+ optional double cpu_suspend = 1;
+
+ optional double cpu_idle = 2;
+
+ optional double cpu_active = 3;
+
+ message CpuCluster {
+ optional int32 id = 1;
+ optional double cluster_power = 2;
+ optional int32 cores = 3;
+ repeated int64 speed = 4;
+ repeated double core_power = 5;
+ }
+
+ repeated CpuCluster cpu_cluster = 40;
+
+ optional double wifi_scan = 4;
+
+ optional double wifi_on = 5;
+
+ optional double wifi_active = 6;
+
+ optional double wifi_controller_idle = 7;
+
+ optional double wifi_controller_rx = 8;
+
+ optional double wifi_controller_tx = 9;
+
+ repeated double wifi_controller_tx_levels = 10;
+
+ optional double wifi_controller_operating_voltage = 11;
+
+ optional double bluetooth_controller_idle = 12;
+
+ optional double bluetooth_controller_rx = 13;
+
+ optional double bluetooth_controller_tx = 14;
+
+ optional double bluetooth_controller_operating_voltage = 15;
+
+ optional double modem_controller_sleep = 16;
+
+ optional double modem_controller_idle = 17;
+
+ optional double modem_controller_rx = 18;
+
+ repeated double modem_controller_tx = 19;
+
+ optional double modem_controller_operating_voltage = 20;
+
+ optional double gps_on = 21;
+
+ repeated double gps_signal_quality_based = 22;
+
+ optional double gps_operating_voltage = 23;
+
+ optional double bluetooth_on = 24;
+
+ optional double bluetooth_active = 25;
+
+ optional double bluetooth_at_cmd = 26;
+
+ optional double ambient_display = 27;
+
+ optional double screen_on = 28;
+
+ optional double radio_on = 29;
+
+ optional double radio_scanning = 30;
+
+ optional double radio_active = 31;
+
+ optional double screen_full = 32;
+
+ optional double audio = 33;
+
+ optional double video = 34;
+
+ optional double flashlight = 35;
+
+ optional double memory = 36;
+
+ optional double camera = 37;
+
+ optional double wifi_batched_scan = 38;
+
+ optional double battery_capacity = 39;
}
/**
@@ -2703,5 +2979,5 @@ message ProcStats {
* Pulled from PowerProfile.java
*/
message PowerProfile {
- optional com.android.internal.os.PowerProfileProto power_profile_proto = 1;
-} \ No newline at end of file
+ optional PowerProfileProto power_profile = 1;
+}
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
index c501c9f818b9..543a748adedb 100644
--- a/cmds/statsd/src/hash.cpp
+++ b/cmds/statsd/src/hash.cpp
@@ -16,6 +16,10 @@
#include "hash.h"
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
namespace android {
namespace os {
namespace statsd {
@@ -67,8 +71,10 @@ uint32_t Hash32(const char *data, size_t n, uint32_t seed) {
switch (n) {
case 3:
h ^= ByteAs32(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs32(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs32(data[0]);
h *= m;
@@ -104,16 +110,22 @@ uint64_t Hash64(const char* data, size_t n, uint64_t seed) {
switch (n) {
case 7:
h ^= ByteAs64(data[6]) << 48;
+ FALLTHROUGH_INTENDED;
case 6:
h ^= ByteAs64(data[5]) << 40;
+ FALLTHROUGH_INTENDED;
case 5:
h ^= ByteAs64(data[4]) << 32;
+ FALLTHROUGH_INTENDED;
case 4:
h ^= ByteAs64(data[3]) << 24;
+ FALLTHROUGH_INTENDED;
case 3:
h ^= ByteAs64(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs64(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs64(data[0]);
h *= m;
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a5dac0836238..6b8c12a893e8 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -46,6 +46,27 @@ struct log_reader_thread_data {
sp<StatsService> service;
};
+
+sp<StatsService> gStatsService = nullptr;
+
+void sigHandler(int sig) {
+ if (gStatsService != nullptr) {
+ gStatsService->Terminate();
+ }
+}
+
+void registerSigHandler()
+{
+ struct sigaction sa;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = sigHandler;
+ sigaction(SIGHUP, &sa, nullptr);
+ sigaction(SIGINT, &sa, nullptr);
+ sigaction(SIGQUIT, &sa, nullptr);
+ sigaction(SIGTERM, &sa, nullptr);
+}
+
int main(int /*argc*/, char** /*argv*/) {
// Set up the looper
sp<Looper> looper(Looper::prepare(0 /* opts */));
@@ -60,23 +81,25 @@ int main(int /*argc*/, char** /*argv*/) {
::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
// Create the service
- sp<StatsService> service = new StatsService(looper);
- if (defaultServiceManager()->addService(String16("stats"), service) != 0) {
+ gStatsService = new StatsService(looper);
+ if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
ALOGE("Failed to add service as AIDL service");
return -1;
}
- auto ret = service->registerAsService();
+ auto ret = gStatsService->registerAsService();
if (ret != ::android::OK) {
ALOGE("Failed to add service as HIDL service");
return 1; // or handle error
}
- service->sayHiToStatsCompanion();
+ registerSigHandler();
+
+ gStatsService->sayHiToStatsCompanion();
- service->Startup();
+ gStatsService->Startup();
- sp<StatsSocketListener> socketListener = new StatsSocketListener(service);
+ sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
ALOGI("using statsd socket");
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ab0b23cc009d..10ed7f3ebaa1 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -271,6 +271,7 @@ message ConfigMetricsReport {
ADB_DUMP = 5;
CONFIG_RESET = 6;
STATSCOMPANION_DIED = 7;
+ TERMINATION_SIGNAL_RECEIVED = 8;
}
optional DumpReportReason dump_report_reason = 8;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fc0c1dc43874..0aa053580a6d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -107,20 +107,6 @@ public final class BluetoothDevice implements Parcelable {
"android.bluetooth.device.action.FOUND";
/**
- * Broadcast Action: Remote device disappeared.
- * <p>Sent when a remote device that was found in the last discovery is not
- * found in the current discovery.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String ACTION_DISAPPEARED =
- "android.bluetooth.device.action.DISAPPEARED";
-
- /**
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
@@ -1971,9 +1957,7 @@ public final class BluetoothDevice implements Parcelable {
* <p>The remote device will be authenticated and communication on this socket will be
* encrypted.
* <p> Use this socket if an authenticated socket link is possible. Authentication refers
- * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
- * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
- * int)}.
+ * to the authentication of the link key to prevent man-in-the-middle type of attacks.
*
* @param psm dynamic PSM value from remote device
* @return a CoC #BluetoothSocket ready for an outgoing connection
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 758c68db1c5f..4e886250b4fa 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,8 +203,8 @@ public final class BluetoothServerSocket implements Closeable {
/**
* Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
* Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
- * {@link BluetoothAdapter.listenUsingL2capChannel()} or {@link
- * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
+ * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
+ * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
* method is called on non-L2CAP server sockets.
*
* @return the assigned PSM or LE_PSM value depending on transport
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ca96d5026247..8913748e0c48 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3955,6 +3955,12 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
/**
+ * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state.
+ * @hide
+ */
+ public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE";
+
+ /**
* The name of the extra used to define the text to be processed, as a
* CharSequence. Note that this may be a styled CharSequence, so you must use
* {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5926af6f9082..0a4f4eb8506c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1408,5 +1408,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* @attr ref android.R.styleable#AndroidManifestLayout_minHeight
*/
public final int minHeight;
+
+ /**
+ * Returns if this {@link WindowLayout} has specified bounds.
+ * @hide
+ */
+ public boolean hasSpecifiedSize() {
+ return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
+ }
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 24675d301f4a..1673c28279b0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2440,17 +2440,17 @@ public class PackageParser {
}
- final int NS = PermissionManager.SPLIT_PERMISSIONS.length;
+ final int NS = PermissionManager.SPLIT_PERMISSIONS.size();
for (int is=0; is<NS; is++) {
final PermissionManager.SplitPermissionInfo spi =
- PermissionManager.SPLIT_PERMISSIONS[is];
+ PermissionManager.SPLIT_PERMISSIONS.get(is);
if (pkg.applicationInfo.targetSdkVersion >= spi.getTargetSdk()
- || !pkg.requestedPermissions.contains(spi.getRootPermission())) {
+ || !pkg.requestedPermissions.contains(spi.getSplitPermission())) {
continue;
}
- final String[] newPerms = spi.getNewPermissions();
- for (int in = 0; in < newPerms.length; in++) {
- final String perm = newPerms[in];
+ final List<String> newPerms = spi.getNewPermissions();
+ for (int in = 0; in < newPerms.size(); in++) {
+ final String perm = newPerms.get(in);
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 486b054e1c00..d4dc181e5eec 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2090,7 +2090,7 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 917644db4202..6609b76faac1 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -133,6 +133,7 @@ public class ContextHubClient implements Closeable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) {
// TODO: Implement this
return false;
@@ -146,6 +147,7 @@ public class ContextHubClient implements Closeable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean unregisterIntent(@NonNull PendingIntent intent) {
// TODO: Implement this
return false;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 36f3586aec2a..f94d69b7fa2d 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -749,6 +749,7 @@ public final class ContextHubManager {
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
@@ -785,6 +786,7 @@ public final class ContextHubManager {
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
@@ -811,6 +813,7 @@ public final class ContextHubManager {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback,
@@ -835,6 +838,7 @@ public final class ContextHubManager {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ee386127bd4d..c496ff4a3bd5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -83,6 +83,7 @@ import java.util.Map;
@SystemService(Context.CONNECTIVITY_SERVICE)
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* A change in network connectivity has occurred. A default connection has either
@@ -2493,6 +2494,7 @@ public class ConnectivityManager {
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
+ printStackTrace();
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
@@ -2513,6 +2515,7 @@ public class ConnectivityManager {
*/
@Deprecated
public void reportBadNetwork(Network network) {
+ printStackTrace();
try {
// One of these will be ignored because it matches system's current state.
// The other will trigger the necessary reevaluation.
@@ -2535,6 +2538,7 @@ public class ConnectivityManager {
* Internet using {@code network} or {@code false} if not.
*/
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ printStackTrace();
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
@@ -3073,6 +3077,7 @@ public class ConnectivityManager {
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+ printStackTrace();
checkCallbackNotNull(callback);
Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
final NetworkRequest request;
@@ -3332,6 +3337,7 @@ public class ConnectivityManager {
* {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
@@ -3355,6 +3361,7 @@ public class ConnectivityManager {
* corresponding NetworkRequest you'd like to remove. Cannot be null.
*/
public void releaseNetworkRequest(PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.releasePendingNetworkRequest(operation);
@@ -3439,6 +3446,7 @@ public class ConnectivityManager {
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(request.networkCapabilities, operation);
@@ -3520,6 +3528,7 @@ public class ConnectivityManager {
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ printStackTrace();
checkCallbackNotNull(networkCallback);
final List<NetworkRequest> reqs = new ArrayList<>();
// Find all requests associated to this callback and stop callback triggers immediately.
@@ -3948,4 +3957,19 @@ public class ConnectivityManager {
throw e.rethrowFromSystemServer();
}
}
+
+ private void printStackTrace() {
+ if (DEBUG) {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 3; i < callStack.length; i++) {
+ final String stackTrace = callStack[i].toString();
+ if (stackTrace == null || stackTrace.contains("android.os")) {
+ break;
+ }
+ sb.append(" [").append(stackTrace).append("]");
+ }
+ Log.d(TAG, "StackLog:" + sb.toString());
+ }
+ }
}
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
new file mode 100644
index 000000000000..53037b2499cd
--- /dev/null
+++ b/core/java/android/os/DumpstateOptions.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Options passed to dumpstate service.
+ *
+ * @hide
+ */
+public final class DumpstateOptions implements Parcelable {
+ // If true the caller can get callbacks with per-section
+ // progress details.
+ private final boolean mGetSectionDetails;
+ // Name of the caller.
+ private final String mName;
+
+ public DumpstateOptions(Parcel in) {
+ mGetSectionDetails = in.readBoolean();
+ mName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mGetSectionDetails);
+ out.writeString(mName);
+ }
+
+ public static final Parcelable.Creator<DumpstateOptions> CREATOR =
+ new Parcelable.Creator<DumpstateOptions>() {
+ public DumpstateOptions createFromParcel(Parcel in) {
+ return new DumpstateOptions(in);
+ }
+
+ public DumpstateOptions[] newArray(int size) {
+ return new DumpstateOptions[size];
+ }
+ };
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index df3aae2c901c..5f656207255a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -55,7 +55,7 @@ public class GraphicsEnvironment {
* Set up GraphicsEnvironment
*/
public void setup(Context context, Bundle coreSettings) {
- setupGpuLayers(context, coreSettings);
+ setupGpuLayers(context);
setupAngle(context, coreSettings);
chooseDriver(context);
}
@@ -81,54 +81,27 @@ public class GraphicsEnvironment {
}
/**
- * Return the debug layer app's on-disk and in-APK lib directories
- */
- private static String getDebugLayerAppPaths(Context context, String app) {
- ApplicationInfo appInfo;
- try {
- appInfo = context.getPackageManager().getApplicationInfo(
- app, PackageManager.MATCH_ALL);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
- return null;
- }
-
- String abi = chooseAbi(appInfo);
-
- StringBuilder sb = new StringBuilder();
- sb.append(appInfo.nativeLibraryDir)
- .append(File.pathSeparator);
- sb.append(appInfo.sourceDir)
- .append("!/lib/")
- .append(abi);
- String paths = sb.toString();
-
- if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
-
- return paths;
- }
-
- /**
* Set up layer search paths for all apps
* If debuggable, check for additional debug settings
*/
- private void setupGpuLayers(Context context, Bundle coreSettings) {
+ private void setupGpuLayers(Context context) {
String layerPaths = "";
// Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable or device is rooted
+ // 1. App is debuggable
// 2. ENABLE_GPU_DEBUG_LAYERS is true
// 3. Package name is equal to GPU_DEBUG_APP
- if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
+ if (isDebuggable(context)) {
- int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ int enable = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
if (enable != 0) {
- String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
+ String gpuDebugApp = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.GPU_DEBUG_APP);
String packageName = context.getPackageName();
@@ -142,22 +115,8 @@ public class GraphicsEnvironment {
// the layers specified by the app.
layerPaths = mDebugLayerPath + ":";
-
- // If there is a debug layer app specified, add its path.
- String gpuDebugLayerApp =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
- if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
- Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
- String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
- if (paths != null) {
- // Append the path so files placed in the app's base directory will
- // override the external path
- layerPaths += paths + ":";
- }
- }
-
- String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+ String layers = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.GPU_DEBUG_LAYERS);
Log.i(TAG, "Debug layer list: " + layers);
if (layers != null && !layers.isEmpty()) {
@@ -331,7 +290,6 @@ public class GraphicsEnvironment {
return null;
}
- private static native int getCanLoadSystemLibraries();
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDriverPath(String path);
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 274b36aa1807..5d5e5e233b35 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,8 @@ package android.os;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
*
* Defines a message containing a description and arbitrary data object that can be
@@ -111,7 +113,13 @@ public final class Message implements Parcelable {
/*package*/ int flags;
- /*package*/ long when;
+ /**
+ * The targeted delivery time of this message. The time-base is
+ * {@link SystemClock#uptimeMillis}.
+ * @hide Only for use within the tests.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public long when;
/*package*/ Bundle data;
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index aa44eb7e3a26..7ffb22f189b8 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -25,7 +25,9 @@ import android.content.Context;
import com.android.internal.annotations.Immutable;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* System level service for accessing the permission capabilities of the platform.
@@ -40,26 +42,28 @@ public final class PermissionManager {
*
* @hide
*/
- public static final SplitPermissionInfo[] SPLIT_PERMISSIONS = new SplitPermissionInfo[]{
+ public static final List<SplitPermissionInfo> SPLIT_PERMISSIONS = Arrays.asList(
// READ_EXTERNAL_STORAGE is always required when an app requests
// WRITE_EXTERNAL_STORAGE, because we can't have an app that has
// write access without read access. The hack here with the target
// target SDK version ensures that this grant is always done.
new SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
+ Collections.singletonList(android.Manifest.permission.READ_EXTERNAL_STORAGE),
android.os.Build.VERSION_CODES.CUR_DEVELOPMENT + 1),
new SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
- new String[]{android.Manifest.permission.READ_CALL_LOG},
+ Collections.singletonList(android.Manifest.permission.READ_CALL_LOG),
android.os.Build.VERSION_CODES.JELLY_BEAN),
new SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
- new String[]{android.Manifest.permission.WRITE_CALL_LOG},
+ Collections.singletonList(android.Manifest.permission.WRITE_CALL_LOG),
android.os.Build.VERSION_CODES.JELLY_BEAN),
new SplitPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION,
- new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+ Collections.singletonList(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
android.os.Build.VERSION_CODES.P0),
new SplitPermissionInfo(Manifest.permission.ACCESS_COARSE_LOCATION,
- new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
- android.os.Build.VERSION_CODES.P0)};
+ Collections.singletonList(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
+ android.os.Build.VERSION_CODES.P0));
private final @NonNull Context mContext;
@@ -74,7 +78,7 @@ public final class PermissionManager {
}
/**
- * Get list of permissions that have been split into more granular or dependent permissions.
+ * Get set of permissions that have been split into more granular or dependent permissions.
*
* <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
* {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
@@ -82,7 +86,7 @@ public final class PermissionManager {
* the location permission only grants location access while the app is in foreground. This
* would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
* such an old app asks for a location permission (i.e. the
- * {@link SplitPermissionInfo#getRootPermission()}), then the
+ * {@link SplitPermissionInfo#getSplitPermission()}), then the
* {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
* {@{@link SplitPermissionInfo#getNewPermissions}) is added.
*
@@ -91,8 +95,9 @@ public final class PermissionManager {
*
* @return All permissions that are split.
*/
- public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
- return Arrays.asList(SPLIT_PERMISSIONS);
+ public @NonNull
+ List<SplitPermissionInfo> getSplitPermissions() {
+ return SPLIT_PERMISSIONS;
}
/**
@@ -101,21 +106,35 @@ public final class PermissionManager {
*/
@Immutable
public static final class SplitPermissionInfo {
- private final @NonNull String mRootPerm;
- private final @NonNull String[] mNewPerms;
+ private final @NonNull String mSplitPerm;
+ private final @NonNull List<String> mNewPerms;
private final int mTargetSdk;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SplitPermissionInfo that = (SplitPermissionInfo) o;
+ return mTargetSdk == that.mTargetSdk
+ && Objects.equals(mSplitPerm, that.mSplitPerm);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSplitPerm, mTargetSdk);
+ }
+
/**
* Get the permission that is split.
*/
- public @NonNull String getRootPermission() {
- return mRootPerm;
+ public @NonNull String getSplitPermission() {
+ return mSplitPerm;
}
/**
* Get the permissions that are added.
*/
- public @NonNull String[] getNewPermissions() {
+ public @NonNull List<String> getNewPermissions() {
return mNewPerms;
}
@@ -126,9 +145,9 @@ public final class PermissionManager {
return mTargetSdk;
}
- private SplitPermissionInfo(@NonNull String rootPerm, @NonNull String[] newPerms,
+ private SplitPermissionInfo(@NonNull String rootPerm, @NonNull List<String> newPerms,
int targetSdk) {
- mRootPerm = rootPerm;
+ mSplitPerm = rootPerm;
mNewPerms = newPerms;
mTargetSdk = targetSdk;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c6e457436025..acb75778e08e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11631,12 +11631,6 @@ public final class Settings {
public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers";
/**
- * Addition app for GPU layer discovery
- * @hide
- */
- public static final String GPU_DEBUG_LAYER_APP = "gpu_debug_layer_app";
-
- /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated This functionality is no longer available as of
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index b461c0daaca5..7af9db8ebf32 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -405,8 +405,8 @@ public abstract class TextClassifierService extends Service {
PackageManager.MATCH_SYSTEM_ONLY);
if ((ri == null) || (ri.serviceInfo == null)) {
- Slog.w(LOG_TAG, String.format("Package or service not found in package %s",
- packageName));
+ Slog.w(LOG_TAG, String.format("Package or service not found in package %s for user %d",
+ packageName, context.getUserId()));
return null;
}
final ServiceInfo si = ri.serviceInfo;
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index 2dc4f6001a06..648bd1bba20c 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -29,8 +29,33 @@ import android.text.TextPaint;
import android.text.TextUtils;
/**
- * Sets the text color, size, style, and typeface to match a TextAppearance
- * resource.
+ * Sets the text appearance using the given
+ * {@link android.R.styleable#TextAppearance TextAppearance} attributes.
+ * By default {@link TextAppearanceSpan} only changes the specified attributes in XML.
+ * {@link android.R.styleable#TextAppearance_textColorHighlight textColorHighlight},
+ * {@link android.R.styleable#TextAppearance_textColorHint textColorHint},
+ * {@link android.R.styleable#TextAppearance_textAllCaps textAllCaps} and
+ * {@link android.R.styleable#TextAppearance_fallbackLineSpacing fallbackLineSpacing}
+ * are not supported by {@link TextAppearanceSpan}.
+ *
+ * {@see android.widget.TextView#setTextAppearance(int)}
+ *
+ * @attr ref android.R.styleable#TextAppearance_fontFamily
+ * @attr ref android.R.styleable#TextAppearance_textColor
+ * @attr ref android.R.styleable#TextAppearance_textColorLink
+ * @attr ref android.R.styleable#TextAppearance_textFontWeight
+ * @attr ref android.R.styleable#TextAppearance_textSize
+ * @attr ref android.R.styleable#TextAppearance_textStyle
+ * @attr ref android.R.styleable#TextAppearance_typeface
+ * @attr ref android.R.styleable#TextAppearance_shadowColor
+ * @attr ref android.R.styleable#TextAppearance_shadowDx
+ * @attr ref android.R.styleable#TextAppearance_shadowDy
+ * @attr ref android.R.styleable#TextAppearance_shadowRadius
+ * @attr ref android.R.styleable#TextAppearance_elegantTextHeight
+ * @attr ref android.R.styleable#TextAppearance_letterSpacing
+ * @attr ref android.R.styleable#TextAppearance_fontFeatureSettings
+ * @attr ref android.R.styleable#TextAppearance_fontVariationSettings
+ *
*/
public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
private final String mFamilyName;
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index f428c798d7f5..e9f1edf52b5f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -245,9 +245,8 @@ public final class DisplayCutout {
* passed, it's treated as an empty rectangle (0,0)-(0,0).
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
- public DisplayCutout(
- Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop,
- @Nullable Rect boundRight, @Nullable Rect boundBottom) {
+ public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
+ @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
this(safeInsets.toRect(), boundLeft, boundTop, boundRight, boundBottom, true);
}
@@ -262,7 +261,7 @@ public final class DisplayCutout {
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
- public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) {
+ public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
this(safeInsets, extractBoundsFromList(safeInsets, boundingRects),
true /* copyArguments */);
}
@@ -313,18 +312,20 @@ public final class DisplayCutout {
for (int i = 0; i < sortedBounds.length; ++i) {
sortedBounds[i] = ZERO_RECT;
}
- for (Rect bound : boundingRects) {
- // There will be at most one non-functional area per short edge of the device, and none
- // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
- // TODO(b/117199965): Refine the logic to handle edge cases.
- if (bound.left == 0) {
- sortedBounds[BOUNDS_POSITION_LEFT] = bound;
- } else if (bound.top == 0) {
- sortedBounds[BOUNDS_POSITION_TOP] = bound;
- } else if (safeInsets.right > 0) {
- sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
- } else if (safeInsets.bottom > 0) {
- sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ if (safeInsets != null && boundingRects != null) {
+ for (Rect bound : boundingRects) {
+ // There is at most one non-functional area per short edge of the device, but none
+ // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
+ // TODO(b/117199965): Refine the logic to handle edge cases.
+ if (bound.left == 0) {
+ sortedBounds[BOUNDS_POSITION_LEFT] = bound;
+ } else if (bound.top == 0) {
+ sortedBounds[BOUNDS_POSITION_TOP] = bound;
+ } else if (safeInsets.right > 0) {
+ sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
+ } else if (safeInsets.bottom > 0) {
+ sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ }
}
}
return sortedBounds;
@@ -389,6 +390,7 @@ public final class DisplayCutout {
* @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
* returned.
*/
+ @NonNull
public List<Rect> getBoundingRects() {
List<Rect> result = new ArrayList<>();
for (Rect bound : getBoundingRectsAll()) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9d06680c4c07..f74c2341d816 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3521,7 +3521,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Typeface mFontTypeface = null;
boolean mFontFamilyExplicit = false;
int mTypefaceIndex = -1;
- int mStyleIndex = -1;
+ int mTextStyle = 0;
int mFontWeight = -1;
boolean mAllCaps = false;
int mShadowColor = 0;
@@ -3547,7 +3547,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " mFontTypeface:" + mFontTypeface + "\n"
+ " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
+ " mTypefaceIndex:" + mTypefaceIndex + "\n"
- + " mStyleIndex:" + mStyleIndex + "\n"
+ + " mTextStyle:" + mTextStyle + "\n"
+ " mFontWeight:" + mFontWeight + "\n"
+ " mAllCaps:" + mAllCaps + "\n"
+ " mShadowColor:" + mShadowColor + "\n"
@@ -3672,7 +3672,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mFontFamilyExplicit = true;
break;
case com.android.internal.R.styleable.TextAppearance_textStyle:
- attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex);
+ attributes.mTextStyle = appearance.getInt(attr, attributes.mTextStyle);
break;
case com.android.internal.R.styleable.TextAppearance_textFontWeight:
attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight);
@@ -3742,7 +3742,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mFontFamily = null;
}
setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
- attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight);
+ attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight);
if (attributes.mShadowColor != 0) {
setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy,
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index e4724ff45b9e..8dc97fe86eb3 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -66,6 +66,7 @@ public class LooperStats implements Looper.Observer {
session = session == null ? new DispatchSession() : session;
session.startTimeMicro = getElapsedRealtimeMicro();
session.cpuStartMicro = getThreadTimeMicro();
+ session.systemUptimeMillis = getSystemUptimeMillis();
return session;
}
@@ -85,12 +86,18 @@ public class LooperStats implements Looper.Observer {
entry.messageCount++;
if (session != DispatchSession.NOT_SAMPLED) {
entry.recordedMessageCount++;
- long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
- long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+ final long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+ final long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
entry.totalLatencyMicro += latency;
entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
entry.cpuUsageMicro += cpuUsage;
entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+ if (msg.getWhen() > 0) {
+ final long delay = Math.max(0L, session.systemUptimeMillis - msg.getWhen());
+ entry.delayMillis += delay;
+ entry.maxDelayMillis = Math.max(entry.maxDelayMillis, delay);
+ entry.recordedDelayMessageCount++;
+ }
}
}
}
@@ -206,6 +213,10 @@ public class LooperStats implements Looper.Observer {
return SystemClock.elapsedRealtimeNanos() / 1000;
}
+ protected long getSystemUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
protected boolean shouldCollectDetailedData() {
return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
}
@@ -214,6 +225,7 @@ public class LooperStats implements Looper.Observer {
static final DispatchSession NOT_SAMPLED = new DispatchSession();
public long startTimeMicro;
public long cpuStartMicro;
+ public long systemUptimeMillis;
}
private static class Entry {
@@ -228,6 +240,9 @@ public class LooperStats implements Looper.Observer {
public long maxLatencyMicro;
public long cpuUsageMicro;
public long maxCpuUsageMicro;
+ public long recordedDelayMessageCount;
+ public long delayMillis;
+ public long maxDelayMillis;
Entry(Message msg, boolean isInteractive) {
this.workSourceUid = msg.workSourceUid;
@@ -251,6 +266,9 @@ public class LooperStats implements Looper.Observer {
maxLatencyMicro = 0;
cpuUsageMicro = 0;
maxCpuUsageMicro = 0;
+ delayMillis = 0;
+ maxDelayMillis = 0;
+ recordedDelayMessageCount = 0;
}
static int idFor(Message msg, boolean isInteractive) {
@@ -281,6 +299,9 @@ public class LooperStats implements Looper.Observer {
public final long maxLatencyMicros;
public final long cpuUsageMicros;
public final long maxCpuUsageMicros;
+ public final long maxDelayMillis;
+ public final long delayMillis;
+ public final long recordedDelayMessageCount;
ExportedEntry(Entry entry) {
this.workSourceUid = entry.workSourceUid;
@@ -301,6 +322,9 @@ public class LooperStats implements Looper.Observer {
this.maxLatencyMicros = entry.maxLatencyMicro;
this.cpuUsageMicros = entry.cpuUsageMicro;
this.maxCpuUsageMicros = entry.maxCpuUsageMicro;
+ this.delayMillis = entry.delayMillis;
+ this.maxDelayMillis = entry.maxDelayMillis;
+ this.recordedDelayMessageCount = entry.recordedDelayMessageCount;
}
}
}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index bf31c7d8ad85..1ee4269d974b 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -29,7 +29,6 @@ import android.util.Slog;
import com.android.internal.util.FastPrintWriter;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.File;
import java.io.FileInputStream;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 0a787b99c0ac..d68e8f88fc5a 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -331,13 +331,11 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
- // Allow Product to customize system configs around libs, features, permissions and apps
- int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
- ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+ // Allow Product to customize all system configs
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow /product_services to customize system configs around libs, features, permissions
// and apps.
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 92235ad494a7..b70485d9a0ea 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,10 +23,6 @@
namespace {
-int getCanLoadSystemLibraries_native() {
- return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
-}
-
void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {
ScopedUtfChars pathChars(env, path);
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
@@ -55,7 +51,6 @@ void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) {
}
const JNINativeMethod g_methods[] = {
- { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
diff --git a/core/proto/android/internal/powerprofile.proto b/core/proto/android/internal/powerprofile.proto
index 9dd5e7ee556c..b0c8b5638a72 100644
--- a/core/proto/android/internal/powerprofile.proto
+++ b/core/proto/android/internal/powerprofile.proto
@@ -35,7 +35,7 @@ message PowerProfileProto {
repeated double core_power = 5;
}
- repeated CpuCluster cpu_cluster = 41;
+ repeated CpuCluster cpu_cluster = 40;
optional double wifi_scan = 4;
@@ -85,27 +85,27 @@ message PowerProfileProto {
optional double ambient_display = 27;
- optional double screen_on = 29;
+ optional double screen_on = 28;
- optional double radio_on = 30;
+ optional double radio_on = 29;
- optional double radio_scanning = 31;
+ optional double radio_scanning = 30;
- optional double radio_active = 32;
+ optional double radio_active = 31;
- optional double screen_full = 33;
+ optional double screen_full = 32;
- optional double audio = 34;
+ optional double audio = 33;
- optional double video = 35;
+ optional double video = 34;
- optional double flashlight = 36;
+ optional double flashlight = 35;
- optional double memory = 37;
+ optional double memory = 36;
- optional double camera = 38;
+ optional double camera = 37;
- optional double wifi_batched_scan = 39;
+ optional double wifi_batched_scan = 38;
- optional double battery_capacity = 40;
+ optional double battery_capacity = 39;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 47dbc0716c94..a02602ee5d99 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -397,10 +397,9 @@ message GlobalSettingsProto {
// Ordered GPU debug layer list
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// App will load ANGLE instead of native GLES drivers.
optional SettingProto angle_enabled_app = 3;
- // App that can provide layer libraries.
- optional SettingProto debug_layer_app = 4;
}
optional Gpu gpu = 59;
diff --git a/proto/src/stats_enums.proto b/core/proto/android/stats/enums.proto
index 6c892cfeae6c..2320a01b324c 100644
--- a/proto/src/stats_enums.proto
+++ b/core/proto/android/stats/enums.proto
@@ -16,8 +16,7 @@
syntax = "proto2";
-package android.os.statsd;
-option java_package = "com.android.os";
+package android.stats;
option java_outer_classname = "StatsEnums";
enum EventType {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d2c00f2a9547..401ffa36f5bd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -138,7 +138,6 @@
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
<protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
- <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 632c37fd54d2..60abd9468179 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -450,7 +450,6 @@ public class SettingsBackupTest {
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.ANGLE_ENABLED_APP,
- Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index c8d994c4f6c1..8e4f2cd2fbff 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -103,6 +103,18 @@ public class DisplayCutoutTest {
equalTo(new Rect[]{ZERO_RECT, boundTop, ZERO_RECT, boundBottom}));
}
+ @Test
+ public void testExtractBoundsFromList_nullBoundingRects() {
+ Rect safeInsets = new Rect(0, 0, 0, 0);
+ assertThat(extractBoundsFromList(safeInsets, null /* boundingRects */),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
+
+ @Test
+ public void testExtractBoundsFromList_nullSafeInsets() {
+ assertThat(extractBoundsFromList(null /* safeInsets */, Collections.emptyList()),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
@Test
public void hasCutout() throws Exception {
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0c8dd9d6ed59..f637b7c7ec32 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -77,9 +77,13 @@ public final class LooperStatsTest {
Message message = mHandlerFirst.obtainMessage(1000);
message.workSourceUid = 1000;
+ message.when = looperStats.getSystemUptimeMillis();
+
+ looperStats.tickUptime(30);
Object token = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(10);
+ looperStats.tickUptime(200);
looperStats.messageDispatched(token, message);
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -98,6 +102,10 @@ public final class LooperStatsTest {
assertThat(entry.maxLatencyMicros).isEqualTo(100);
assertThat(entry.cpuUsageMicros).isEqualTo(10);
assertThat(entry.maxCpuUsageMicros).isEqualTo(10);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
+ assertThat(entry.delayMillis).isEqualTo(30);
+ assertThat(entry.maxDelayMillis).isEqualTo(30);
+
}
@Test
@@ -215,6 +223,56 @@ public final class LooperStatsTest {
}
@Test
+ public void testDispatchDelayIsRecorded() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+
+ // Dispatched right on time.
+ Message message1 = mHandlerFirst.obtainMessage(1000);
+ message1.when = looperStats.getSystemUptimeMillis();
+ Object token1 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token1, message1);
+
+ // Dispatched 100ms late.
+ Message message2 = mHandlerFirst.obtainMessage(1000);
+ message2.when = looperStats.getSystemUptimeMillis() - 100;
+ Object token2 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token2, message2);
+
+ // No target dispatching time.
+ Message message3 = mHandlerFirst.obtainMessage(1000);
+ message3.when = 0;
+ Object token3 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token3, message3);
+
+ // Dispatched too soon (should never happen).
+ Message message4 = mHandlerFirst.obtainMessage(1000);
+ message4.when = looperStats.getSystemUptimeMillis() + 200;
+ Object token4 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token4, message4);
+
+ // Dispatched 300ms late.
+ Message message5 = mHandlerFirst.obtainMessage(1000);
+ message5.when = looperStats.getSystemUptimeMillis() - 300;
+ Object token5 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token5, message5);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(1);
+
+ LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.messageCount).isEqualTo(5);
+ assertThat(entry.recordedMessageCount).isEqualTo(5);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(4);
+ assertThat(entry.delayMillis).isEqualTo(400);
+ assertThat(entry.maxDelayMillis).isEqualTo(300);
+ }
+
+ @Test
public void testDataNotCollectedBeforeDeviceStateSet() {
TestableLooperStats looperStats = new TestableLooperStats(1, 100);
looperStats.setDeviceState(null);
@@ -385,6 +443,7 @@ public final class LooperStatsTest {
private int mCount;
private long mRealtimeMicros;
private long mThreadTimeMicros;
+ private long mUptimeMillis;
private int mSamplingInterval;
TestableLooperStats(int samplingInterval, int sizeCap) {
@@ -401,6 +460,10 @@ public final class LooperStatsTest {
mThreadTimeMicros += micros;
}
+ void tickUptime(long millis) {
+ mUptimeMillis += millis;
+ }
+
@Override
protected long getElapsedRealtimeMicro() {
return INITIAL_MICROS + mRealtimeMicros;
@@ -412,6 +475,11 @@ public final class LooperStatsTest {
}
@Override
+ protected long getSystemUptimeMillis() {
+ return INITIAL_MICROS / 1000 + mUptimeMillis;
+ }
+
+ @Override
protected boolean shouldCollectDetailedData() {
return mCount++ % mSamplingInterval == 0;
}
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 8414d6a6b866..b65fb9cd24ec 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -2525,9 +2525,7 @@ public abstract class ColorSpace {
gamma == 1.0 ? DoubleUnaryOperator.identity() :
x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
min, max, id);
- mTransferParameters = gamma == 1.0 ?
- new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0f), gamma) :
- new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+ mTransferParameters = new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
}
/**
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 7efe5220873e..f41cc7ee5095 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,6 @@ import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -570,7 +569,7 @@ public final class Icon implements Parcelable {
* Version of createWithResource that takes Resources. Do not use.
* @hide
*/
- @SystemApi
+ @UnsupportedAppUsage
public static Icon createWithResource(Resources res, @DrawableRes int resId) {
if (res == null) {
throw new IllegalArgumentException("Resource must not be null.");
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 3821bc7ab063..21ce1b8392d2 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -27,7 +27,6 @@ import android.system.Os;
import android.system.OsConstants;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.IOException;
diff --git a/keystore/OWNERS b/keystore/OWNERS
new file mode 100644
index 000000000000..a63ca46df2a6
--- /dev/null
+++ b/keystore/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+robbarnes@google.com
+swillden@google.com
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 2395b24f7136..b96a5853b9dc 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3252,7 +3252,7 @@ public class ExifInterface {
int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
// The following code limits the size of thumbnail size not to overflow EXIF data area.
- thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
+ thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
|| mMimeType == IMAGE_TYPE_RW2) {
thumbnailOffset += mExifOffset;
@@ -3981,6 +3981,10 @@ public class ExifInterface {
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
+
+ public int getLength() {
+ return mLength;
+ }
}
// An output stream to write EXIF data area, which can be written in either little or big endian
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 0e5cbe4e20b7..5604ffd83deb 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -3620,6 +3620,17 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
&& getState() == PLAYER_STATE_ERROR) {
status = CALL_STATUS_INVALID_OPERATION;
} else {
+ if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
+ synchronized (mTaskLock) {
+ if (!mPendingTasks.isEmpty()) {
+ Task nextTask = mPendingTasks.get(0);
+ if (nextTask.mMediaCallType == mMediaCallType) {
+ throw new CommandSkippedException(
+ "consecutive seekTo is skipped except last one");
+ }
+ }
+ }
+ }
process();
}
} catch (IllegalStateException e) {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index cdaabdcda20f..d0ca04bb07c2 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -184,7 +184,6 @@ public class DeviceDiscoveryService extends Service {
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
- intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
index 164fc5a5af3d..9855565c1335 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -26,15 +26,16 @@ class CutoutAvoidingToolbar : LinearLayout {
private var _insets: WindowInsets? = null
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@@ -81,8 +82,4 @@ class CutoutAvoidingToolbar : LinearLayout {
requestLayout()
}
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
index a4a3d3d835e0..fc7e8b008a54 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -17,7 +17,6 @@
package com.android.egg.paint
import android.content.Context
-import android.content.res.Resources
import android.graphics.*
import android.provider.Settings
import android.util.AttributeSet
@@ -26,7 +25,6 @@ import android.view.MotionEvent
import android.view.View
import android.view.WindowInsets
import java.util.concurrent.TimeUnit
-import android.util.Log
import android.provider.Settings.System
import org.json.JSONObject
@@ -86,11 +84,11 @@ public class Painting : View, SpotFilter.Plotter {
}
var bitmap: Bitmap? = null
- var paperColor : Int = 0xFFFFFFFF.toInt()
+ var paperColor: Int = 0xFFFFFFFF.toInt()
private var _paintCanvas: Canvas? = null
private val _bitmapLock = Object()
-
+
private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private var _lastX = 0f
private var _lastY = 0f
@@ -113,7 +111,9 @@ public class Painting : View, SpotFilter.Plotter {
FADE_TO_BLACK_CF
synchronized(_bitmapLock) {
- c.drawBitmap(bitmap, 0f, 0f, pt)
+ bitmap?.let {
+ c.drawBitmap(bitmap!!, 0f, 0f, pt)
+ }
}
invalidate()
}
@@ -122,18 +122,22 @@ public class Painting : View, SpotFilter.Plotter {
}
constructor(context: Context) : super(context) {
- init(null, 0)
+ init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
+ init()
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
+ init()
}
- private fun init(attrs: AttributeSet?, defStyle: Int) {
+ private fun init() {
loadDevicePressureData()
}
@@ -264,7 +268,7 @@ public class Painting : View, SpotFilter.Plotter {
super.onDraw(canvas)
bitmap?.let {
- canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+ canvas.drawBitmap(bitmap!!, 0f, 0f, _drawPaint)
}
}
@@ -330,8 +334,8 @@ public class Painting : View, SpotFilter.Plotter {
}
if (bits.width != oldBits.height || bits.height != oldBits.width) {
matrix.postScale(
- bits.width.toFloat()/oldBits.height,
- bits.height.toFloat()/oldBits.width)
+ bits.width.toFloat() / oldBits.height,
+ bits.height.toFloat() / oldBits.width)
}
c.matrix = matrix
}
@@ -350,9 +354,10 @@ public class Painting : View, SpotFilter.Plotter {
val invertPaint = Paint()
invertPaint.colorFilter = INVERT_CF
synchronized(_bitmapLock) {
- _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+ bitmap?.let {
+ _paintCanvas?.drawBitmap(bitmap!!, 0f, 0f, invertPaint)
+ }
}
invalidate()
}
}
-
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
index 86b11e7be81e..460fa3a7241f 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -17,19 +17,10 @@
package com.android.egg.paint
import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Rect
-import android.graphics.drawable.Drawable
-import android.text.TextPaint
-import android.transition.ChangeBounds
import android.transition.Transition
import android.transition.TransitionListenerAdapter
-import android.transition.TransitionManager
import android.util.AttributeSet
import android.view.*
-import android.view.animation.OvershootInterpolator
import android.widget.FrameLayout
class ToolbarView : FrameLayout {
@@ -44,15 +35,16 @@ class ToolbarView : FrameLayout {
}
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
@@ -70,8 +62,4 @@ class ToolbarView : FrameLayout {
return super.onApplyWindowInsets(insets)
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index da1354be63d2..8745a330311a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -662,9 +662,6 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.ANGLE_ENABLED_APP,
GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
- dumpSetting(s, p,
- Settings.Global.GPU_DEBUG_LAYER_APP,
- GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7a38899f37f7..f138685e9810 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,8 +24,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
- android:background="@color/notification_guts_bg_color"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
+ android:background="@color/notification_guts_bg_color">
<!-- Package Info -->
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436dea9207..d033057cdb78 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
android:paddingEnd="@dimen/status_bar_padding_end"
android:orientation="horizontal"
>
- <ViewStub
- android:id="@+id/operator_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/operator_name" />
<FrameLayout
android:layout_height="match_parent"
android:layout_width="0dp"
@@ -70,6 +65,12 @@
android:layout_width="match_parent"
android:clipChildren="false"
>
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
+
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e1c71fae7559..42e19aace0c3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -761,6 +761,8 @@
<string name="quick_settings_cast_device_default_description">Ready to cast</string>
<!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_detail_empty_text">No devices available</string>
+ <!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
@@ -1999,6 +2001,9 @@
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_details">Open details.</string>
+ <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>
+
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d24d82bd7ee..3007b6e68b78 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -736,14 +736,19 @@ public class ScreenDecorations extends SystemUI implements Tunable {
switch (gravity) {
case Gravity.TOP:
out.set(displayCutout.getBoundingRectTop());
+ break;
case Gravity.LEFT:
out.set(displayCutout.getBoundingRectLeft());
+ break;
case Gravity.BOTTOM:
out.set(displayCutout.getBoundingRectBottom());
+ break;
case Gravity.RIGHT:
out.set(displayCutout.getBoundingRectRight());
+ break;
+ default:
+ out.setEmpty();
}
- out.setEmpty();
}
private void localBounds(Rect out) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index ed78048c8746..921db6901626 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
import java.util.LinkedHashMap;
import java.util.Set;
@@ -58,16 +59,18 @@ public class CastTile extends QSTileImpl<BooleanState> {
private final CastController mController;
private final CastDetailAdapter mDetailAdapter;
private final KeyguardMonitor mKeyguard;
+ private final NetworkController mNetworkController;
private final Callback mCallback = new Callback();
private final ActivityStarter mActivityStarter;
private Dialog mDialog;
- private boolean mRegistered;
+ private boolean mWifiConnected;
public CastTile(QSHost host) {
super(host);
mController = Dependency.get(CastController.class);
mDetailAdapter = new CastDetailAdapter();
mKeyguard = Dependency.get(KeyguardMonitor.class);
+ mNetworkController = Dependency.get(NetworkController.class);
mActivityStarter = Dependency.get(ActivityStarter.class);
}
@@ -87,10 +90,12 @@ public class CastTile extends QSTileImpl<BooleanState> {
if (listening) {
mController.addCallback(mCallback);
mKeyguard.addCallback(mCallback);
+ mNetworkController.addCallback(mSignalCallback);
} else {
mController.setDiscovering(false);
mController.removeCallback(mCallback);
mKeyguard.removeCallback(mCallback);
+ mNetworkController.removeCallback(mSignalCallback);
}
}
@@ -112,6 +117,9 @@ public class CastTile extends QSTileImpl<BooleanState> {
@Override
protected void handleClick() {
+ if (getState().state == Tile.STATE_UNAVAILABLE) {
+ return;
+ }
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
showDetail(true);
@@ -164,13 +172,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
if (!state.value && connecting) {
state.label = mContext.getString(R.string.quick_settings_connecting);
}
- state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
: R.drawable.ic_qs_cast_off);
+ if (mWifiConnected) {
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.secondaryLabel = "";
+ state.contentDescription = state.contentDescription + ","
+ + mContext.getString(R.string.accessibility_quick_settings_open_details);
+ state.expandedAccessibilityClassName = Button.class.getName();
+ } else {
+ state.state = Tile.STATE_UNAVAILABLE;
+ String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
+ state.secondaryLabel = noWifi;
+ state.contentDescription = state.contentDescription + ", " + mContext.getString(
+ R.string.accessibility_quick_settings_not_available, noWifi);
+ }
mDetailAdapter.updateItems(devices);
- state.expandedAccessibilityClassName = Button.class.getName();
- state.contentDescription = state.contentDescription + ","
- + mContext.getString(R.string.accessibility_quick_settings_open_details);
}
@Override
@@ -192,6 +209,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
: mContext.getString(R.string.quick_settings_cast_device_default_name);
}
+ private final NetworkController.SignalCallback mSignalCallback =
+ new NetworkController.SignalCallback() {
+ @Override
+ public void setWifiIndicators(boolean enabled,
+ NetworkController.IconState statusIcon,
+ NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
+ String description, boolean isTransient, String statusLabel) {
+ // statusIcon.visible has the connected status information
+ boolean enabledAndConnected = enabled && qsIcon.visible;
+ if (enabledAndConnected != mWifiConnected) {
+ mWifiConnected = enabledAndConnected;
+ refreshState();
+ }
+ }
+ };
+
private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
@Override
public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2450e448c4f7..24665eac76a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -491,6 +491,10 @@ public class CarStatusBar extends StatusBar implements
@Override
public void onStateChanged(int newState) {
super.onStateChanged(newState);
+ if (mFullscreenUserSwitcher == null) {
+ return; // Not using the full screen user switcher.
+ }
+
if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
if (!mFullscreenUserSwitcher.isVisible()) {
// Current execution path continues to set state after this, thus we deffer the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 9acaf21c41f5..c66bbb1696ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -48,6 +48,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final NotificationStackScrollLayout mStackScroller;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mClockView;
+ private final View mOperatorNameView;
private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelView mPanelView;
private final Consumer<ExpandableNotificationRow>
@@ -65,8 +66,10 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> updatePanelTranslation();
+ private boolean mAnimationsEnabled = true;
Point mPoint;
+
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
@@ -75,7 +78,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
statusbarView.findViewById(R.id.heads_up_status_bar_view),
statusbarView.findViewById(R.id.notification_stack_scroller),
statusbarView.findViewById(R.id.notification_panel),
- statusbarView.findViewById(R.id.clock));
+ statusbarView.findViewById(R.id.clock),
+ statusbarView.findViewById(R.id.operator_name_frame));
}
@VisibleForTesting
@@ -85,7 +89,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
HeadsUpStatusBarView headsUpStatusBarView,
NotificationStackScrollLayout stackScroller,
NotificationPanelView panelView,
- View clockView) {
+ View clockView,
+ View operatorNameView) {
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(this);
@@ -101,6 +106,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
+ mOperatorNameView = operatorNameView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mDarkIconDispatcher.addDarkReceiver(this);
@@ -230,20 +236,52 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mShown = isShown;
if (isShown) {
mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
- CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+ show(mHeadsUpStatusBarView);
+ hide(mClockView, View.INVISIBLE);
+ if (mOperatorNameView != null) {
+ hide(mOperatorNameView, View.INVISIBLE);
+ }
} else {
- CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+ show(mClockView);
+ if (mOperatorNameView != null) {
+ show(mOperatorNameView);
+ }
+ hide(mHeadsUpStatusBarView, View.GONE);
}
}
}
+ /**
+ * Hides the view and sets the state to endState when finished.
+ *
+ * @param view The view to hide.
+ * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+ * @see View#setVisibility(int)
+ *
+ */
+ private void hide(View view, int endState) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+ 0 /* delay */, () -> view.setVisibility(endState));
+ } else {
+ view.setVisibility(endState);
+ }
+ }
+
+ private void show(View view) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ } else {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @VisibleForTesting
+ void setAnimationsEnabled(boolean enabled) {
+ mAnimationsEnabled = enabled;
+ }
+
@VisibleForTesting
public boolean isShown() {
return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2a4595b980ac..8ac867727e65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -361,6 +361,8 @@ public class KeyguardBouncer {
} else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
onFullyHidden();
mExpansionCallback.onFullyHidden();
+ } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
+ mExpansionCallback.onStartingToHide();
}
}
@@ -481,6 +483,7 @@ public class KeyguardBouncer {
public interface BouncerExpansionCallback {
void onFullyShown();
+ void onStartingToHide();
void onFullyHidden();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7c84df91fffa..e85ff8ef22c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -519,7 +519,14 @@ public class KeyguardStatusBarView extends RelativeLayout
mStatusIconContainer.setAlpha(alpha);
mStatusIconContainer.setVisibility(visibility);
- mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+ float iconsX = -mCurrentBurnInOffsetX;
+ if (mMultiUserSwitch.getVisibility() == VISIBLE) {
+ // Squared alpha to add a nice easing curve and avoid overlap during animation.
+ mMultiUserAvatar.setAlpha(alpha * alpha);
+ iconsX += mMultiUserAvatar.getPaddingLeft() + mMultiUserAvatar.getWidth()
+ + mMultiUserAvatar.getPaddingRight();
+ }
+ mSystemIconsContainer.setTranslationX(iconsX * mDarkAmount);
mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
updateIconsAndTextColors();
}
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 3db1456446a0..ac3608bc622a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,6 +84,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
@Override
+ public void onStartingToHide() {
+ updateStates();
+ }
+
+ @Override
public void onFullyHidden() {
updateStates();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
new file mode 100644
index 000000000000..d9412ecd9a3a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quicksettings.Tile;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CastTileTest extends SysuiTestCase {
+
+ @Mock
+ private CastController mController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private KeyguardMonitor mKeyguard;
+ @Mock
+ private NetworkController mNetworkController;
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ NetworkController.SignalCallback mCallback;
+
+ private TestableLooper mTestableLooper;
+ private CastTile mCastTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mController = mDependency.injectMockDependency(CastController.class);
+ mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+ mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
+ mNetworkController = mDependency.injectMockDependency(NetworkController.class);
+
+ when(mHost.getContext()).thenReturn(mContext);
+
+ mCastTile = new CastTile(mHost);
+
+ // We are not setting the mocks to listening, so we trigger a first refresh state to
+ // set the initial state
+ mCastTile.refreshState();
+
+ mCastTile.handleSetListening(true);
+ ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
+ verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
+ mCallback = signalCallbackArgumentCaptor.getValue();
+
+ }
+
+ @Test
+ public void testStateUnavailable_wifiDisabled() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateUnavailable_wifiNotConnected() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateActive_wifiEnabledAndCasting() {
+ CastController.CastDevice device = mock(CastController.CastDevice.class);
+ device.state = CastController.CastDevice.STATE_CONNECTED;
+ Set<CastController.CastDevice> devices = new HashSet<>();
+ devices.add(device);
+ when(mController.getCastDevices()).thenReturn(devices);
+
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateInactive_wifiEnabledNotCasting() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index a4004ae2d7cc..10b0d834b36b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -54,6 +54,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
private HeadsUpManagerPhone mHeadsUpManager;
+ private View mOperatorNameView;
@Before
public void setUp() throws Exception {
@@ -63,13 +64,15 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+ mOperatorNameView = new View(mContext);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
mHeadsUpManager,
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
- new View(mContext));
+ new View(mContext),
+ mOperatorNameView);
mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
}
@@ -116,6 +119,22 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
}
@Test
+ public void testOperatorNameViewUpdated() {
+ mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+ }
+
+ @Test
public void testHeaderReadFromOldController() {
mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f);
@@ -125,6 +144,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
+ new View(mContext),
new View(mContext));
newController.readFrom(mHeadsUpAppearanceController);
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 a7954f2aa199..020682b6b4e8 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
@@ -170,13 +170,17 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
- mBouncer.setExpansion(1);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
verify(mFalsingManager).onBouncerHidden();
verify(mExpansionCallback).onFullyHidden();
- mBouncer.setExpansion(0);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
verify(mFalsingManager).onBouncerShown();
verify(mExpansionCallback).onFullyShown();
+
+ verify(mExpansionCallback, never()).onStartingToHide();
+ mBouncer.setExpansion(0.9f);
+ verify(mExpansionCallback).onStartingToHide();
}
@Test
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5e87707c39e6..d86de5dfd799 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6549,6 +6549,21 @@ message MetricsEvent {
// Subtype: The importance of a notification has been changed
ADJUSTMENT_KEY_IMPORTANCE = 1580;
+ // OPEN: Settings > Network & internet > Mobile network > Choose network
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_NETWORK_SELECT = 1581;
+
+ // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_DATA_DIALOG = 1582;
+
+ // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_ROAMING_DIALOG = 1583;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index be353458cf44..2fa2941efe7f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -4,6 +4,7 @@ java_library_static {
aidl: {
include_dirs: [
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"system/core/storaged/binder",
"system/netd/server/binder",
"system/vold/binder",
@@ -11,6 +12,7 @@ java_library_static {
},
srcs: [
"java/**/*.java",
+ ":dumpstate_aidl",
":netd_aidl",
":netd_metrics_aidl",
":installd_aidl",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b8db2d067a6e..4b77c69aba2b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5513,15 +5513,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (networkAgent.isVPN()) {
// Temporarily disable the default proxy (not global).
- synchronized (mProxyTracker.mProxyLock) {
- if (!mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = true;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(null);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(false);
// TODO: support proxy per network.
}
@@ -5543,15 +5535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- synchronized (mProxyTracker.mProxyLock) {
- if (mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = false;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(true);
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
disconnectAndDestroyNetwork(networkAgent);
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 96ce6a4ee6a4..6677541b1b32 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -109,14 +109,28 @@ public class LooperStatsService extends Binder {
"max_latency_micros",
"total_cpu_micros",
"max_cpu_micros",
+ "recorded_delay_message_count",
+ "total_delay_millis",
+ "max_delay_millis",
"exception_count"));
pw.println(header);
for (LooperStats.ExportedEntry entry : entries) {
- pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
- entry.threadName, entry.handlerClassName, entry.messageName,
- entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
- entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
- entry.maxCpuUsageMicros, entry.exceptionCount);
+ pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
+ entry.workSourceUid,
+ entry.threadName,
+ entry.handlerClassName,
+ entry.messageName,
+ entry.isInteractive,
+ entry.messageCount,
+ entry.recordedMessageCount,
+ entry.totalLatencyMicros,
+ entry.maxLatencyMicros,
+ entry.cpuUsageMicros,
+ entry.maxCpuUsageMicros,
+ entry.recordedDelayMessageCount,
+ entry.delayMillis,
+ entry.maxDelayMillis,
+ entry.exceptionCount);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
deleted file mode 100644
index f44ee7a234ca..000000000000
--- a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
+++ /dev/null
@@ -1,65 +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.server.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
-
-/**
- * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
- * inside {@link ActivityOptions#getLaunchBounds()}.
- */
-public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
- private final ActivityStackSupervisor mSupervisor;
-
- ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
- mSupervisor = activityStackSupervisor;
- }
-
- @Override
- public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source, ActivityOptions options,
- LaunchParams currentParams, LaunchParams outParams) {
- // We only care about figuring out bounds for activities.
- if (activity == null) {
- return RESULT_SKIP;
- }
-
- // Activity must be resizeable in the specified task.
- if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
- && (activity.isResizeable() || (task != null && task.isResizeable())))) {
- return RESULT_SKIP;
- }
-
- final Rect bounds = options.getLaunchBounds();
-
- // Bounds weren't valid.
- if (bounds == null || bounds.isEmpty()) {
- return RESULT_SKIP;
- }
-
- outParams.mBounds.set(bounds);
-
- // When this is the most explicit position specification so we should not allow further
- // modification of the position.
- return RESULT_DONE;
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37167c688d87..acf7a73332b7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10184,6 +10184,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
sb.append("Process: ").append(processName).append("\n");
sb.append("PID: ").append(process.pid).append("\n");
+ sb.append("UID: ").append(process.uid).append("\n");
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 18cdb054e648..7080e2bd58fd 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -110,7 +110,7 @@ import com.android.server.LocalServices;
* data for Tron, logcat, event logs and {@link android.app.WaitResult}.
*
* Tests:
- * atest SystemMetricsFunctionalTests
+ * atest CtsActivityManagerDeviceTestCases:ActivityMetricsLoggerTests
*/
class ActivityMetricsLogger {
@@ -351,18 +351,24 @@ class ActivityMetricsLogger {
+ " processRunning=" + processRunning
+ " processSwitch=" + processSwitch);
- // If we are already in an existing transition, only update the activity name, but not the
- // other attributes.
final int windowingMode = launchedActivity != null
? launchedActivity.getWindowingMode()
: WINDOWING_MODE_UNDEFINED;
-
+ final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (mCurrentTransitionStartTime == INVALID_START_TIME) {
+ // No transition is active ignore this launch.
+ return;
+ }
+
+ if (launchedActivity != null && launchedActivity.nowVisible) {
+ // Launched activity is already visible. We cannot measure windows drawn delay.
+ reset(true /* abort */, info);
return;
}
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (launchedActivity != null && info != null) {
+ // If we are already in an existing transition, only update the activity name, but not
+ // the other attributes.
info.launchedActivity = launchedActivity;
return;
}
@@ -371,7 +377,6 @@ class ActivityMetricsLogger {
mWindowingModeTransitionInfo.size() > 0 && info == null;
if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
-
// Failed to launch or it was not a process switch, so we don't care about the timing.
reset(true /* abort */, info);
return;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index db9e59c23858..864bf2d77b59 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -227,7 +227,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
@Override
- protected ConfigurationContainer getChildAt(int index) {
+ protected TaskRecord getChildAt(int index) {
return mTaskHistory.get(index);
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 13b16b2fb84c..33f949fccfb0 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1606,13 +1606,18 @@ class ActivityStarter {
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
- mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
-
mLaunchParams.reset();
mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
options, mLaunchParams);
+ if (mLaunchParams.hasPreferredDisplay()) {
+ mPreferredDisplayId = mLaunchParams.mPreferredDisplayId;
+ } else {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+ ensureValidPreferredDisplayId(r);
+
mLaunchMode = r.launchMode;
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
@@ -1704,6 +1709,24 @@ class ActivityStarter {
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
}
+ /**
+ * Ensure preferred display ID matches the starting activity.
+ */
+ private void ensureValidPreferredDisplayId(ActivityRecord startingActivity) {
+ // Check if the Activity is a VR activity. If so, the activity should be launched in
+ // main display.
+ if (startingActivity != null && startingActivity.requestedVrComponent != null) {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+
+ // Get the virtual display ID from ActivityStackManagerService. If that's set we should
+ // always use that.
+ final int displayId = mService.mVr2dDisplayId;
+ if (displayId != INVALID_DISPLAY) {
+ mPreferredDisplayId = displayId;
+ }
+ }
+
private void sendNewTaskResultRequestIfNeeded() {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
@@ -1883,44 +1906,6 @@ class ActivityStarter {
}
/**
- * Returns the ID of the display to use for a new activity. If the device is in VR mode,
- * then return the Vr mode's virtual display ID. If not, if the activity was started with
- * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID
- * set, use that to launch the activity.
- */
- private int getPreferedDisplayId(
- ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) {
- // Check if the Activity is a VR activity. If so, the activity should be launched in
- // main display.
- if (startingActivity != null && startingActivity.requestedVrComponent != null) {
- return DEFAULT_DISPLAY;
- }
-
- // Get the virtual display id from ActivityManagerService.
- int displayId = mService.mVr2dDisplayId;
- if (displayId != INVALID_DISPLAY) {
- if (DEBUG_STACK) {
- Slog.d(TAG, "getSourceDisplayId :" + displayId);
- }
- return displayId;
- }
-
- // If the caller requested a display, prefer that display.
- final int launchDisplayId =
- (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY;
- if (launchDisplayId != INVALID_DISPLAY) {
- return launchDisplayId;
- }
-
- displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY;
- // If the activity has a displayId set explicitly, launch it on the same displayId.
- if (displayId != INVALID_DISPLAY) {
- return displayId;
- }
- return DEFAULT_DISPLAY;
- }
-
- /**
* Figure out which task and activity to bring to front when we have found an existing matching
* activity record in history. May also clear the task if needed.
* @param intentActivity Existing matching activity.
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 2ca134465cd6..09c152ef5135 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -56,10 +56,6 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 6415c3ee7f72..218d9080c2c0 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -16,6 +16,13 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
import android.annotation.IntDef;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo.WindowLayout;
@@ -26,13 +33,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
/**
* {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
* registered {@link LaunchParamsModifier}s.
@@ -58,11 +58,7 @@ class LaunchParamsController {
*/
void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
// {@link TaskLaunchParamsModifier} handles window layout preferences.
- registerModifier(new TaskLaunchParamsModifier());
-
- // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
- // registered last (applied first) out of the defaults.
- registerModifier(new ActivityLaunchParamsModifier(supervisor));
+ registerModifier(new TaskLaunchParamsModifier(supervisor));
}
/**
@@ -226,27 +222,41 @@ class LaunchParamsController {
@IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
@interface Result {}
- // Returned when the modifier does not want to influence the bounds calculation
+ /** Returned when the modifier does not want to influence the bounds calculation */
int RESULT_SKIP = 0;
- // Returned when the modifier has changed the bounds and would like its results to be the
- // final bounds applied.
+ /**
+ * Returned when the modifier has changed the bounds and would like its results to be the
+ * final bounds applied.
+ */
int RESULT_DONE = 1;
- // Returned when the modifier has changed the bounds but is okay with other modifiers
- // influencing the bounds.
+ /**
+ * Returned when the modifier has changed the bounds but is okay with other modifiers
+ * influencing the bounds.
+ */
int RESULT_CONTINUE = 2;
/**
- * Called when asked to calculate {@link LaunchParams}.
- * @param task The {@link TaskRecord} currently being positioned.
- * @param layout The specified {@link WindowLayout}.
- * @param activity The {@link ActivityRecord} currently being positioned.
- * @param source The {@link ActivityRecord} activity was started from.
- * @param options The {@link ActivityOptions} specified for the activity.
- * @param currentParams The current {@link LaunchParams}. This can differ from the initial
- * params as it represents the modified params up to this point.
- * @param outParams The resulting {@link LaunchParams} after all calculations.
- * @return A {@link Result} representing the result of the
- * {@link LaunchParams} calculation.
+ * Returns the launch params that the provided activity launch params should be overridden
+ * to. {@link LaunchParamsModifier} can use this for various purposes, including: 1)
+ * Providing default bounds if the launch bounds have not been provided. 2) Repositioning
+ * the task so it doesn't get placed over an existing task. 3) Resizing the task so that its
+ * dimensions match the activity's requested orientation.
+ *
+ * @param task Can be: 1) the target task in which the source activity wants to
+ * launch the target activity; 2) a newly created task that Android
+ * gives a chance to override its launching bounds; 3) {@code null} if
+ * this is called to override an activity's launching bounds.
+ * @param layout Desired layout when activity is first launched.
+ * @param activity Activity that is being started. This can be {@code null} on
+ * re-parenting an activity to a new task (e.g. for
+ * Picture-In-Picture). Tasks being created because an activity was
+ * launched should have this be non-null.
+ * @param source the Activity that launched a new task. Could be {@code null}.
+ * @param options {@link ActivityOptions} used to start the activity with.
+ * @param currentParams launching params after the process of last {@link
+ * LaunchParamsModifier}.
+ * @param outParams the result params to be set.
+ * @return see {@link LaunchParamsModifier.Result}
*/
@Result
int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index 92f1cc34be92..fd34d180ebc0 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -16,304 +16,770 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.graphics.Rect;
+import android.os.Build;
import android.util.Slog;
import android.view.Gravity;
-import com.android.internal.annotations.VisibleForTesting;
+
import com.android.server.am.LaunchParamsController.LaunchParams;
import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
import java.util.ArrayList;
+import java.util.List;
/**
- * Determines where a launching task should be positioned and sized on the display.
- *
- * The modifier is fairly simple. For the new task it tries default position based on the gravity
- * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
- * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
- * all possible shifts, it gives up and puts the task in the original position.
- *
- * Note that the only gravities of concern are the corners and the center.
+ * The class that defines the default launch params for tasks.
*/
class TaskLaunchParamsModifier implements LaunchParamsModifier {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
+ private static final boolean DEBUG = false;
- // Determines how close window frames/corners have to be to call them colliding.
- private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
+ // A mask for SUPPORTS_SCREEN that indicates the activity supports resize.
+ private static final int SUPPORTS_SCREEN_RESIZEABLE_MASK =
+ ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+ | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
- // Task will receive dimensions based on available dimensions divided by this.
- private static final int WINDOW_SIZE_DENOMINATOR = 2;
+ // Screen size of Nexus 5x
+ private static final int DEFAULT_PORTRAIT_PHONE_WIDTH_DP = 412;
+ private static final int DEFAULT_PORTRAIT_PHONE_HEIGHT_DP = 732;
- // Task will receive margins based on available dimensions divided by this.
- private static final int MARGIN_SIZE_DENOMINATOR = 4;
+ // Allowance of size matching.
+ private static final int EPSILON = 2;
- // If task bounds collide with some other, we will step and try again until we find a good
- // position. The step will be determined by using dimensions and dividing it by this.
+ // Cascade window offset.
+ private static final int CASCADING_OFFSET_DP = 75;
+
+ // Threshold how close window corners have to be to call them colliding.
+ private static final int BOUNDS_CONFLICT_THRESHOLD = 4;
+
+ // Divide display size by this number to get each step to adjust bounds to avoid conflict.
private static final int STEP_DENOMINATOR = 16;
// We always want to step by at least this.
private static final int MINIMAL_STEP = 1;
- // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
- // reaches the end of stack bounds.
- private static final boolean ALLOW_RESTART = true;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Rect mTmpBounds = new Rect();
+ private final int[] mTmpDirections = new int[2];
- private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
- private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
- private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+ private StringBuilder mLogBuilder;
- private final Rect mAvailableRect = new Rect();
- private final Rect mTmpProposal = new Rect();
- private final Rect mTmpOriginal = new Rect();
+ TaskLaunchParamsModifier(ActivityStackSupervisor supervisor) {
+ mSupervisor = supervisor;
+ }
- /**
- * Tries to set task's bound in a way that it won't collide with any other task. By colliding
- * we mean that two tasks have left-top corner very close to each other, so one might get
- * obfuscated by the other one.
- */
@Override
public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options,
LaunchParams currentParams, LaunchParams outParams) {
- // We can only apply positioning if we're in a freeform stack.
- if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
- return RESULT_SKIP;
- }
+ initLogBuilder(task, activity);
+ final int result = calculate(task, layout, activity, source, options, currentParams,
+ outParams);
+ outputLog();
+ return result;
+ }
- final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
+ private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
+ // STEP 1: Determine the display to launch the activity/task.
+ final int displayId = getPreferredLaunchDisplay(options, source, currentParams);
+ outParams.mPreferredDisplayId = displayId;
+ ActivityDisplay display = mSupervisor.getActivityDisplay(displayId);
+ if (DEBUG) {
+ appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
+ + display.getWindowingMode());
+ }
- mAvailableRect.set(task.getParent().getBounds());
+ final ActivityRecord root;
+ if (task != null) {
+ root = (task.getRootActivity() == null ? activity : task.getRootActivity());
+ } else {
+ root = activity;
+ }
+ // STEP 2: Resolve launch windowing mode.
+ // STEP 2.1: Determine if any parameter has specified initial bounds. That might be the
+ // launch bounds from activity options, or size/gravity passed in layout. It also treat the
+ // launch windowing mode in options as a suggestion for future resolution.
+ int launchMode = options != null ? options.getLaunchWindowingMode()
+ : WINDOWING_MODE_UNDEFINED;
+ // hasInitialBounds is set if either activity options or layout has specified bounds. If
+ // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
+ boolean hasInitialBounds = false;
+ final boolean canApplyFreeformPolicy =
+ canApplyFreeformWindowPolicy(display, root, launchMode);
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(options) && canApplyFreeformPolicy) {
+ hasInitialBounds = true;
+ launchMode = launchMode == WINDOWING_MODE_UNDEFINED
+ ? WINDOWING_MODE_FREEFORM
+ : launchMode;
+ outParams.mBounds.set(options.getLaunchBounds());
+ if (DEBUG) appendLog("activity-options-bounds=" + outParams.mBounds);
+ } else if (launchMode == WINDOWING_MODE_PINNED) {
+ // System controls PIP window's bounds, so don't apply launch bounds.
+ if (DEBUG) appendLog("empty-window-layout-for-pip");
+ } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
+ if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
+ } else if (layout != null && canApplyFreeformPolicy) {
+ getLayoutBounds(display, root, layout, mTmpBounds);
+ if (!mTmpBounds.isEmpty()) {
+ launchMode = WINDOWING_MODE_FREEFORM;
+ outParams.mBounds.set(mTmpBounds);
+ hasInitialBounds = true;
+ if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
+ } else {
+ if (DEBUG) appendLog("empty-window-layout");
+ }
+ }
- final Rect resultBounds = outParams.mBounds;
+ // STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has
+ // some opinions on launch mode and launch bounds. If they have opinions and there is no
+ // initial bounds set in parameters. Note the check on display ID is also input param
+ // related because we always defer to callers' suggestion if there is no specific display ID
+ // in options or from source activity.
+ //
+ // If opinions from callers don't need any further resolution, we try to honor that as is as
+ // much as possible later.
+
+ // Flag to indicate if current param needs no further resolution. It's true it current
+ // param isn't freeform mode, or it already has launch bounds.
+ boolean fullyResolvedCurrentParam = false;
+ // We inherit launch params from previous modifiers or LaunchParamsController if options,
+ // layout and display conditions are not contradictory to their suggestions. It's important
+ // to carry over their values because LaunchParamsController doesn't automatically do that.
+ if (!currentParams.isEmpty() && !hasInitialBounds
+ && (!currentParams.hasPreferredDisplay()
+ || displayId == currentParams.mPreferredDisplayId)) {
+ if (currentParams.hasWindowingMode()) {
+ launchMode = currentParams.mWindowingMode;
+ fullyResolvedCurrentParam = (launchMode != WINDOWING_MODE_FREEFORM);
+ if (DEBUG) {
+ appendLog("inherit-" + WindowConfiguration.windowingModeToString(launchMode));
+ }
+ }
- if (layout == null) {
- positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
- getFreeformHeight(mAvailableRect), resultBounds);
- return RESULT_CONTINUE;
+ if (!currentParams.mBounds.isEmpty()) {
+ outParams.mBounds.set(currentParams.mBounds);
+ fullyResolvedCurrentParam = true;
+ if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+ }
}
- int width = getFinalWidth(layout, mAvailableRect);
- int height = getFinalHeight(layout, mAvailableRect);
- int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
- int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- if (verticalGravity == Gravity.TOP) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
- } else {
- positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
- }
- } else if (verticalGravity == Gravity.BOTTOM) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
- } else {
- positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
+ // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
+ // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
+ // are forced to be maximized. The rest of this step is to define the default policy when
+ // there is no initial bounds or a fully resolved current params from callers. Right now we
+ // launch all possible tasks/activities that can handle freeform into freeform mode.
+ if (display.inFreeformWindowingMode()) {
+ if (launchMode == WINDOWING_MODE_PINNED) {
+ if (DEBUG) appendLog("picture-in-picture");
+ } else if (isTaskForcedMaximized(root)) {
+ // We're launching an activity that probably can't handle resizing nicely, so force
+ // it to be maximized even someone suggests launching it in freeform using launch
+ // options.
+ launchMode = WINDOWING_MODE_FULLSCREEN;
+ outParams.mBounds.setEmpty();
+ if (DEBUG) appendLog("forced-maximize");
+ } else if (fullyResolvedCurrentParam) {
+ // Don't adjust launch mode if that's inherited, except when we're launching an
+ // activity that should be forced to maximize.
+ if (DEBUG) appendLog("skip-adjustment-fully-resolved-params");
+ } else if (launchMode != WINDOWING_MODE_FREEFORM
+ && (isNOrGreater(root) || isPreNResizeable(root))) {
+ // We're launching a pre-N and post-D activity that supports resizing, or a post-N
+ // activity. They can handle freeform nicely so launch them in freeform.
+ // Use undefined because we know we're in a freeform display.
+ launchMode = WINDOWING_MODE_UNDEFINED;
+ if (DEBUG) appendLog("should-be-freeform");
}
} else {
- // Some fancy gravity setting that we don't support yet. We just put the activity in the
- // center.
- Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
- + ", positioning in the center instead.");
- positionCenter(tasks, mAvailableRect, width, height, resultBounds);
+ if (DEBUG) appendLog("non-freeform-display");
+ }
+ // If launch mode matches display windowing mode, let it inherit from display.
+ outParams.mWindowingMode = launchMode == display.getWindowingMode()
+ ? WINDOWING_MODE_UNDEFINED : launchMode;
+
+ // STEP 3: Determine final launch bounds based on resolved windowing mode and activity
+ // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
+ // for all other windowing modes that's not freeform mode. One can read comments in
+ // relevant methods to further understand this step.
+ //
+ // We skip making adjustments if the params are fully resolved from previous results and
+ // trust that they are valid.
+ if (!fullyResolvedCurrentParam) {
+ final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
+ : display.getWindowingMode();
+ if (source != null && source.inFreeformWindowingMode()
+ && resolvedMode == WINDOWING_MODE_FREEFORM
+ && outParams.mBounds.isEmpty()
+ && source.getDisplayId() == display.mDisplayId) {
+ // Set bounds to be not very far from source activity.
+ cascadeBounds(source.getBounds(), display, outParams.mBounds);
+ }
+ getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
}
return RESULT_CONTINUE;
}
- @VisibleForTesting
- static int getFreeformStartLeft(Rect bounds) {
- return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR;
+ private int getPreferredLaunchDisplay(@Nullable ActivityOptions options,
+ ActivityRecord source, LaunchParams currentParams) {
+ int displayId = INVALID_DISPLAY;
+ final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
+ if (optionLaunchId != INVALID_DISPLAY) {
+ if (DEBUG) appendLog("display-from-option=" + optionLaunchId);
+ displayId = optionLaunchId;
+ }
+
+ if (displayId == INVALID_DISPLAY && source != null) {
+ final int sourceDisplayId = source.getDisplayId();
+ if (DEBUG) appendLog("display-from-source=" + sourceDisplayId);
+ displayId = sourceDisplayId;
+ }
+
+ if (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) == null) {
+ displayId = INVALID_DISPLAY;
+ }
+ displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
+
+ displayId = (displayId == INVALID_DISPLAY) ? DEFAULT_DISPLAY : displayId;
+
+ return displayId;
+ }
+
+ private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display,
+ @NonNull ActivityRecord root, int launchMode) {
+ return display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM
+ || root.isResizeable();
}
- @VisibleForTesting
- static int getFreeformStartTop(Rect bounds) {
- return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR;
+ private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+ @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+ final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+ final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
+ outBounds.setEmpty();
+ return;
+ }
+
+ final Rect bounds = display.getBounds();
+ final int defaultWidth = bounds.width();
+ final int defaultHeight = bounds.height();
+
+ int width;
+ int height;
+ if (!windowLayout.hasSpecifiedSize()) {
+ outBounds.setEmpty();
+ getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
+ /* hasInitialBounds */ false, outBounds);
+ width = outBounds.width();
+ height = outBounds.height();
+ } else {
+ width = defaultWidth;
+ if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
+ width = windowLayout.width;
+ } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) {
+ width = (int) (width * windowLayout.widthFraction);
+ }
+
+ height = defaultHeight;
+ if (windowLayout.height > 0 && windowLayout.height < defaultHeight) {
+ height = windowLayout.height;
+ } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) {
+ height = (int) (height * windowLayout.heightFraction);
+ }
+ }
+
+ final float fractionOfHorizontalOffset;
+ switch (horizontalGravity) {
+ case Gravity.LEFT:
+ fractionOfHorizontalOffset = 0f;
+ break;
+ case Gravity.RIGHT:
+ fractionOfHorizontalOffset = 1f;
+ break;
+ default:
+ fractionOfHorizontalOffset = 0.5f;
+ }
+
+ final float fractionOfVerticalOffset;
+ switch (verticalGravity) {
+ case Gravity.TOP:
+ fractionOfVerticalOffset = 0f;
+ break;
+ case Gravity.BOTTOM:
+ fractionOfVerticalOffset = 1f;
+ break;
+ default:
+ fractionOfVerticalOffset = 0.5f;
+ }
+
+ outBounds.set(0, 0, width, height);
+ final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
+ final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
+ outBounds.offset(xOffset, yOffset);
}
- @VisibleForTesting
- static int getFreeformWidth(Rect bounds) {
- return bounds.width() / WINDOW_SIZE_DENOMINATOR;
+ /**
+ * Returns if task is forced to maximize.
+ *
+ * There are several cases where we force a task to maximize:
+ * 1) Root activity is targeting pre-Donut, which by default can't handle multiple screen
+ * densities, so resizing will likely cause issues;
+ * 2) Root activity doesn't declare any flag that it supports any screen density, so resizing
+ * may also cause issues;
+ * 3) Root activity is not resizeable, for which we shouldn't allow user resize it.
+ *
+ * @param root the root activity to check against.
+ * @return {@code true} if it should be forced to maximize; {@code false} otherwise.
+ */
+ private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
+ if (root.appInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
+ || (root.appInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
+ return true;
+ }
+
+ return !root.isResizeable();
}
- @VisibleForTesting
- static int getFreeformHeight(Rect bounds) {
- return bounds.height() / WINDOW_SIZE_DENOMINATOR;
+ private boolean isNOrGreater(@NonNull ActivityRecord root) {
+ return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
+ }
+
+ /**
+ * Resolves activity requested orientation to 4 categories:
+ * 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
+ * orientation;
+ * 2) {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} indicating app wants to be in landscape;
+ * 3) {@link ActivityInfo#SCREEN_ORIENTATION_PORTRAIT} indicating app wants to be in portrait;
+ * 4) {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} indicating app can handle any
+ * orientation.
+ *
+ * @param activity the activity to check
+ * @return corresponding resolved orientation value.
+ */
+ private int resolveOrientation(@NonNull ActivityRecord activity) {
+ int orientation = activity.info.screenOrientation;
+ switch (orientation) {
+ case SCREEN_ORIENTATION_NOSENSOR:
+ case SCREEN_ORIENTATION_LOCKED:
+ orientation = SCREEN_ORIENTATION_LOCKED;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+ case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+ case SCREEN_ORIENTATION_USER_LANDSCAPE:
+ case SCREEN_ORIENTATION_LANDSCAPE:
+ if (DEBUG) appendLog("activity-requested-landscape");
+ orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+ case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+ case SCREEN_ORIENTATION_USER_PORTRAIT:
+ case SCREEN_ORIENTATION_PORTRAIT:
+ if (DEBUG) appendLog("activity-requested-portrait");
+ orientation = SCREEN_ORIENTATION_PORTRAIT;
+ break;
+ default:
+ orientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ return orientation;
}
- @VisibleForTesting
- static int getHorizontalStep(Rect bounds) {
- return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP);
+ private boolean isPreNResizeable(ActivityRecord root) {
+ return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
}
- @VisibleForTesting
- static int getVerticalStep(Rect bounds) {
- return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP);
+ private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+ @NonNull Rect outBounds) {
+ outBounds.set(srcBounds);
+ float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
+
+ display.getBounds(mTmpBounds);
+ final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
+ final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
+ outBounds.offset(dx, dy);
}
+ private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
+ @NonNull Rect inOutBounds) {
+ if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
+ // We don't handle letterboxing here. Letterboxing will be handled by valid checks
+ // later.
+ inOutBounds.setEmpty();
+ if (DEBUG) appendLog("maximized-bounds");
+ return;
+ }
+ if (resolvedMode != WINDOWING_MODE_FREEFORM) {
+ // We don't apply freeform bounds adjustment to other windowing modes.
+ if (DEBUG) {
+ appendLog("skip-bounds-" + WindowConfiguration.windowingModeToString(resolvedMode));
+ }
+ return;
+ }
- private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int width = getFreeformWidth(availableRect);
- if (windowLayout.width > 0) {
- width = windowLayout.width;
+ final int orientation = resolveOrientation(root, display, inOutBounds);
+ if (orientation != SCREEN_ORIENTATION_PORTRAIT
+ && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
+ throw new IllegalStateException(
+ "Orientation must be one of portrait or landscape, but it's "
+ + ActivityInfo.screenOrientationToString(orientation));
}
- if (windowLayout.widthFraction > 0) {
- width = (int) (availableRect.width() * windowLayout.widthFraction);
+
+ // First we get the default size we want.
+ getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+ if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
+ // We're here because either input parameters specified initial bounds, or the suggested
+ // bounds have the same size of the default freeform size. We should use the suggested
+ // bounds if possible -- so if app can handle the orientation we just use it, and if not
+ // we transpose the suggested bounds in-place.
+ if (orientation == orientationFromBounds(inOutBounds)) {
+ if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
+ } else {
+ // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
+ centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+ if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
+ }
+ } else {
+ // We are here either because there is no suggested bounds, or the suggested bounds is
+ // a cascade from source activity. We should use the default freeform size and center it
+ // to the center of suggested bounds (or the display if no suggested bounds). The
+ // default size might be too big to center to source activity bounds in display, so we
+ // may need to move it back to the display.
+ centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
+ adjustBoundsToFitInDisplay(display, inOutBounds);
+ if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
}
- return width;
+
+ // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
+ adjustBoundsToAvoidConflict(display, inOutBounds);
}
- private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int height = getFreeformHeight(availableRect);
- if (windowLayout.height > 0) {
- height = windowLayout.height;
+ private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull Rect bounds) {
+ int orientation = resolveOrientation(root);
+
+ if (orientation == SCREEN_ORIENTATION_LOCKED) {
+ orientation = bounds.isEmpty() ? display.getConfiguration().orientation
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
+ : "locked-orientation-from-bounds=" + bounds);
+ }
}
- if (windowLayout.heightFraction > 0) {
- height = (int) (availableRect.height() * windowLayout.heightFraction);
+
+ if (orientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ orientation = bounds.isEmpty() ? SCREEN_ORIENTATION_PORTRAIT
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "default-portrait"
+ : "orientation-from-bounds=" + bounds);
+ }
}
- return height;
- }
- private void positionBottomLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.bottom - height,
- availableRect.left + width, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
+ return orientation;
}
- private void positionBottomRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
- availableRect.right, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
+ private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+ @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());
+ final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
+ final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
+ : portraitWidth;
+ final int defaultHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitWidth
+ : portraitHeight;
+
+ // Get window size based on Nexus 5x screen, we assume that this is enough to show content
+ // of activities.
+ final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
+ final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
+ final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
+ : phonePortraitWidth;
+ final int phoneHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitWidth
+ : phonePortraitHeight;
+
+ // Minimum layout requirements.
+ final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth;
+ final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
+
+ // Final result.
+ final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
+ final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
+
+ bounds.set(0, 0, width, height);
}
- private void positionTopLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.top,
- availableRect.left + width, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
+ /**
+ * 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.
+ */
+ private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+ @NonNull Rect inOutBounds) {
+ if (inOutBounds.isEmpty()) {
+ display.getBounds(inOutBounds);
+ }
+ final int left = inOutBounds.centerX() - width / 2;
+ final int top = inOutBounds.centerY() - height / 2;
+ inOutBounds.set(left, top, left + width, top + height);
}
- private void positionTopRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.top,
- availableRect.right, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
- }
+ private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+
+ if (displayBounds.width() < inOutBounds.width()
+ || displayBounds.height() < inOutBounds.height()) {
+ // There is no way for us to fit the bounds in the display without changing width
+ // or height. Don't even try it.
+ return;
+ }
+
+ final int dx;
+ if (inOutBounds.right > displayBounds.right) {
+ // Right edge is out of display.
+ dx = displayBounds.right - inOutBounds.right;
+ } else if (inOutBounds.left < displayBounds.left) {
+ // Left edge is out of display.
+ dx = displayBounds.left - inOutBounds.left;
+ } else {
+ // Vertical edges are all in display.
+ dx = 0;
+ }
- private void positionCenter(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
- final int defaultFreeformTop = getFreeformStartTop(availableRect);
- mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
- defaultFreeformLeft + width, defaultFreeformTop + height);
- position(tasks, availableRect, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN,
- result);
+ final int dy;
+ if (inOutBounds.top < displayBounds.top) {
+ // Top edge is out of display.
+ dy = displayBounds.top - inOutBounds.top;
+ } else if (inOutBounds.bottom > displayBounds.bottom) {
+ // Bottom edge is out of display.
+ dy = displayBounds.bottom - inOutBounds.bottom;
+ } else {
+ // Horizontal edges are all in display.
+ dy = 0;
+ }
+ inOutBounds.offset(dx, dy);
}
- private void position(ArrayList<TaskRecord> tasks, Rect availableRect,
- Rect proposal, boolean allowRestart, int shiftPolicy, Rect result) {
- mTmpOriginal.set(proposal);
- boolean restarted = false;
- while (boundsConflict(proposal, tasks)) {
- // Unfortunately there is already a task at that spot, so we need to look for some
- // other place.
- shiftStartingPoint(proposal, availableRect, shiftPolicy);
- if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
- // We don't want the task to go outside of the stack, because it won't look
- // nice. Depending on the starting point we either restart, or immediately give up.
- if (!allowRestart) {
- proposal.set(mTmpOriginal);
- break;
- }
- // We must have started not from the top. Let's restart from there because there
- // might be some space there.
- proposal.set(availableRect.left, availableRect.top,
- availableRect.left + proposal.width(),
- availableRect.top + proposal.height());
- restarted = true;
+ /**
+ * Adjusts input bounds to avoid conflict with existing tasks in the display.
+ *
+ * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
+ * directions to find a location where the we can put the bounds in display without conflict
+ * with any other tasks.
+ *
+ * It doesn't try to adjust bounds that's not fully in the given display.
+ *
+ * @param display the display which tasks are to check
+ * @param inOutBounds the bounds used to input initial bounds and output result bounds
+ */
+ private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+ if (!displayBounds.contains(inOutBounds)) {
+ // The initial bounds are already out of display. The scanning algorithm below doesn't
+ // work so well with them.
+ return;
+ }
+
+ final List<TaskRecord> tasksToCheck = new ArrayList<>();
+ for (int i = 0; i < display.getChildCount(); ++i) {
+ ActivityStack<?> stack = display.getChildAt(i);
+ if (!stack.inFreeformWindowingMode()) {
+ continue;
}
- if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
- || proposal.top > getFreeformStartTop(availableRect))) {
- // If we restarted and crossed the initial position, let's not struggle anymore.
- // The user already must have ton of tasks visible, we can just smack the new
- // one in the center.
- proposal.set(mTmpOriginal);
+
+ for (int j = 0; j < stack.getChildCount(); ++j) {
+ tasksToCheck.add(stack.getChildAt(j));
+ }
+ }
+
+ if (!boundsConflict(tasksToCheck, inOutBounds)) {
+ // Current proposal doesn't conflict with any task. Early return to avoid unnecessary
+ // calculation.
+ return;
+ }
+
+ calculateCandidateShiftDirections(displayBounds, inOutBounds);
+ for (int direction : mTmpDirections) {
+ if (direction == Gravity.NO_GRAVITY) {
+ // We exhausted candidate directions, give up.
break;
}
+
+ mTmpBounds.set(inOutBounds);
+ while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ shiftBounds(direction, displayBounds, mTmpBounds);
+ }
+
+ if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ // Found a candidate. Just use this.
+ inOutBounds.set(mTmpBounds);
+ if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
+ return;
+ }
+
+ // Didn't find a conflict free bounds here. Try the next candidate direction.
}
- result.set(proposal);
+
+ // We failed to find a conflict free location. Just keep the original result.
}
- private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- return start.left < availableRect.left;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- return start.right > availableRect.right;
- default: // SHIFT_POLICY_DIAGONAL_DOWN
- return start.right > availableRect.right || start.bottom > availableRect.bottom;
+ /**
+ * Determines scanning directions and their priorities to avoid bounds conflict.
+ *
+ * @param availableBounds bounds that the result must be in
+ * @param initialBounds initial bounds when start scanning
+ */
+ private void calculateCandidateShiftDirections(@NonNull Rect availableBounds,
+ @NonNull Rect initialBounds) {
+ for (int i = 0; i < mTmpDirections.length; ++i) {
+ mTmpDirections[i] = Gravity.NO_GRAVITY;
+ }
+
+ final int oneThirdWidth = (2 * availableBounds.left + availableBounds.right) / 3;
+ final int twoThirdWidth = (availableBounds.left + 2 * availableBounds.right) / 3;
+ final int centerX = initialBounds.centerX();
+ if (centerX < oneThirdWidth) {
+ // Too close to left, just scan to the right.
+ mTmpDirections[0] = Gravity.RIGHT;
+ return;
+ } else if (centerX > twoThirdWidth) {
+ // Too close to right, just scan to the left.
+ mTmpDirections[0] = Gravity.LEFT;
+ return;
}
+
+ final int oneThirdHeight = (2 * availableBounds.top + availableBounds.bottom) / 3;
+ final int twoThirdHeight = (availableBounds.top + 2 * availableBounds.bottom) / 3;
+ final int centerY = initialBounds.centerY();
+ if (centerY < oneThirdHeight || centerY > twoThirdHeight) {
+ // Too close to top or bottom boundary and we're in the middle horizontally, scan
+ // horizontally in both directions.
+ mTmpDirections[0] = Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.LEFT;
+ return;
+ }
+
+ // We're in the center region both horizontally and vertically. Scan in both directions of
+ // primary diagonal.
+ mTmpDirections[0] = Gravity.BOTTOM | Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.TOP | Gravity.LEFT;
}
- private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
- final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
- final int defaultFreeformStepVertical = getVerticalStep(availableRect);
+ private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) {
+ for (TaskRecord task : tasks) {
+ final Rect taskBounds = task.getBounds();
+ final boolean leftClose = Math.abs(taskBounds.left - bounds.left)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean topClose = Math.abs(taskBounds.top - bounds.top)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean rightClose = Math.abs(taskBounds.right - bounds.right)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom)
+ < BOUNDS_CONFLICT_THRESHOLD;
+
+ if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose)
+ || (rightClose && bottomClose)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- posposal.offset(-defaultFreeformStepHorizontal, 0);
+ private void shiftBounds(int direction, @NonNull Rect availableRect,
+ @NonNull Rect inOutBounds) {
+ final int horizontalOffset;
+ switch (direction & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ horizontalOffset = -Math.max(MINIMAL_STEP,
+ availableRect.width() / STEP_DENOMINATOR);
break;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- posposal.offset(defaultFreeformStepHorizontal, 0);
+ case Gravity.RIGHT:
+ horizontalOffset = Math.max(MINIMAL_STEP, availableRect.width() / STEP_DENOMINATOR);
break;
- default: // SHIFT_POLICY_DIAGONAL_DOWN:
- posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
+ default:
+ horizontalOffset = 0;
+ }
+
+ final int verticalOffset;
+ switch (direction & Gravity.VERTICAL_GRAVITY_MASK) {
+ case Gravity.TOP:
+ verticalOffset = -Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
break;
+ case Gravity.BOTTOM:
+ verticalOffset = Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+ break;
+ default:
+ verticalOffset = 0;
}
+
+ inOutBounds.offset(horizontalOffset, verticalOffset);
}
- private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final TaskRecord task = tasks.get(i);
- if (!task.mActivities.isEmpty() && !task.matchParentBounds()) {
- final Rect bounds = task.getOverrideBounds();
- if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
- || closeLeftBottomCorner(proposal, bounds)
- || closeRightBottomCorner(proposal, bounds)) {
- return true;
- }
- }
+ private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+ if (DEBUG) {
+ mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
+ + " activity=" + activity);
}
- return false;
}
- private static final boolean closeLeftTopCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void appendLog(String log) {
+ if (DEBUG) mLogBuilder.append(" ").append(log);
}
- private static final boolean closeRightTopCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void outputLog() {
+ if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
}
- private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private static int orientationFromBounds(Rect bounds) {
+ return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
}
- private static final boolean closeRightBottomCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private static boolean sizeMatches(Rect left, Rect right) {
+ return (Math.abs(right.width() - left.width()) < EPSILON)
+ && (Math.abs(right.height() - left.height()) < EPSILON);
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ca9b25699c1c..30659c1e77a3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1031,6 +1031,11 @@ public class NetworkMonitor extends StateMachine {
result.isPortal() /* isCaptivePortal */,
startTime, endTime);
+ log("isCaptivePortal: isSuccessful()=" + result.isSuccessful() +
+ " isPortal()=" + result.isPortal() +
+ " RedirectUrl=" + result.redirectUrl +
+ " StartTime=" + startTime + " EndTime=" + endTime);
+
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 111c6d2de537..47e85b5fd3ab 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,6 +16,12 @@
package com.android.server.connectivity;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.provider.Settings.Global.HTTP_PROXY;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -47,16 +53,14 @@ public class ProxyTracker {
@NonNull
private final Context mContext;
- // TODO : make this private and import as much managing logic from ConnectivityService as
- // possible
@NonNull
- public final Object mProxyLock = new Object();
+ private final Object mProxyLock = new Object();
// The global proxy is the proxy that is set device-wide, overriding any network-specific
// proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
// this value is only for querying.
@Nullable
@GuardedBy("mProxyLock")
- public ProxyInfo mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
// The default proxy is the proxy that applies to no particular network if the global proxy
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
@@ -64,10 +68,10 @@ public class ProxyTracker {
// when PacManager resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
- public volatile ProxyInfo mDefaultProxy = null;
- // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+ private volatile ProxyInfo mDefaultProxy = null;
+ // Whether the default proxy is enabled.
@GuardedBy("mProxyLock")
- public boolean mDefaultProxyDisabled = false;
+ private boolean mDefaultProxyEnabled = true;
// The object responsible for Proxy Auto Configuration (PAC).
@NonNull
@@ -85,7 +89,7 @@ public class ProxyTracker {
@Nullable
private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+ && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
return null;
}
return proxy;
@@ -123,7 +127,7 @@ public class ProxyTracker {
// This information is already available as a world read/writable jvm property.
synchronized (mProxyLock) {
final ProxyInfo ret = mGlobalProxy;
- if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
+ if ((ret == null) && mDefaultProxyEnabled) return mDefaultProxy;
return ret;
}
}
@@ -146,11 +150,10 @@ public class ProxyTracker {
*/
public void loadGlobalProxy() {
ContentResolver res = mContext.getContentResolver();
- String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
- int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
- String exclList = Settings.Global.getString(res,
- Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+ String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
@@ -175,8 +178,7 @@ public class ProxyTracker {
* Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
*/
public void loadDeprecatedGlobalHttpProxy() {
- final String proxy = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.HTTP_PROXY);
+ final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
if (data.length == 0) {
@@ -259,11 +261,10 @@ public class ProxyTracker {
final ContentResolver res = mContext.getContentResolver();
final long token = Binder.clearCallingIdentity();
try {
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -280,10 +281,7 @@ public class ProxyTracker {
*/
public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
synchronized (mProxyLock) {
- if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
- return;
- }
- if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+ if (Objects.equals(mDefaultProxy, proxyInfo)) return;
if (proxyInfo != null && !proxyInfo.isValid()) {
if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
@@ -304,9 +302,27 @@ public class ProxyTracker {
mDefaultProxy = proxyInfo;
if (mGlobalProxy != null) return;
- if (!mDefaultProxyDisabled) {
+ if (mDefaultProxyEnabled) {
sendProxyBroadcast(proxyInfo);
}
}
}
+
+ /**
+ * Enable or disable the default proxy.
+ *
+ * This sets the flag for enabling/disabling the default proxy and sends the broadcast
+ * if applicable.
+ * @param enabled whether the default proxy should be enabled.
+ */
+ public void setDefaultProxyEnabled(final boolean enabled) {
+ synchronized (mProxyLock) {
+ if (mDefaultProxyEnabled != enabled) {
+ mDefaultProxyEnabled = enabled;
+ if (mGlobalProxy == null && mDefaultProxy != null) {
+ sendProxyBroadcast(enabled ? mDefaultProxy : null);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 7a1da662961c..b29b7cf5a712 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -147,12 +147,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
/**
* Invoked when the underlying binder of this broker has died at the client process.
*/
+ @Override
public void binderDied() {
- try {
- IContextHubClient.Stub.asInterface(this).close();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while closing client on death", e);
- }
+ close();
}
/**
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 3ffc5c53eab6..9c1ac346ce32 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -57,7 +57,7 @@ public final class DeviceIdentifiersPolicyService extends SystemService {
// should use the getSerialForPackage method with the calling package specified.
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
/* callingPackage */ null, "getSerial")) {
- return null;
+ return Build.UNKNOWN;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
@@ -66,7 +66,7 @@ public final class DeviceIdentifiersPolicyService extends SystemService {
public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException {
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
callingPackage, "getSerial")) {
- return null;
+ return Build.UNKNOWN;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 13f084e67494..910860363c26 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2920,7 +2920,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
final PermissionManager.SplitPermissionInfo splitPerm =
splitPermissions.get(splitPermNum);
- final String rootPerm = splitPerm.getRootPermission();
+ final String rootPerm = splitPerm.getSplitPermission();
if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
continue;
@@ -2942,11 +2942,11 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
- final String[] newPerms = splitPerm.getNewPermissions();
+ final List<String> newPerms = splitPerm.getNewPermissions();
- final int numNewPerms = newPerms.length;
+ final int numNewPerms = newPerms.size();
for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
- final String newPerm = newPerms[newPermNum];
+ final String newPerm = newPerms.get(newPermNum);
if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6f644dd70339..0a93653ede56 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1033,8 +1033,8 @@ public final class DefaultPermissionGrantPolicy {
if (applicationInfo != null
&& applicationInfo.targetSdkVersion < splitPerm.getTargetSdk()
- && permissionsWithoutSplits.contains(splitPerm.getRootPermission())) {
- Collections.addAll(permissions, splitPerm.getNewPermissions());
+ && permissionsWithoutSplits.contains(splitPerm.getSplitPermission())) {
+ permissions.addAll(splitPerm.getNewPermissions());
}
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 1cba1c7bed1b..a55b49fe028d 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -95,10 +95,22 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
mIsShowing = showing;
mCallback.onShowingChanged();
- try {
- mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error informing keystore of screen lock", e);
+ int retry = 2;
+ while (retry > 0) {
+ try {
+ mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+ break;
+ } catch (RemoteException e) {
+ if (retry == 2) {
+ Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
+ + " -> refreshing service token and retrying");
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+ } else {
+ Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
+ }
+ --retry;
+ }
}
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index d36ab3f09399..5ce8145fa00e 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -28,7 +28,6 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.textclassifier.ITextClassificationCallback;
import android.service.textclassifier.ITextClassifierService;
import android.service.textclassifier.ITextLinksCallback;
@@ -41,7 +40,6 @@ import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
-import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -275,6 +273,20 @@ public final class TextClassificationManagerService extends ITextClassifierServi
IndentingPrintWriter pw = new IndentingPrintWriter(fout, " ");
TextClassificationManager tcm = mContext.getSystemService(TextClassificationManager.class);
tcm.dump(pw);
+
+ pw.printPair("context", mContext); pw.println();
+ synchronized (mLock) {
+ int size = mUserStates.size();
+ pw.print("Number user states: "); pw.println(size);
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ pw.increaseIndent();
+ UserState userState = mUserStates.valueAt(i);
+ pw.print(i); pw.print(":"); userState.dump(pw); pw.println();
+ pw.decreaseIndent();
+ }
+ }
+ }
}
private static final class PendingRequest implements IBinder.DeathRecipient {
@@ -431,6 +443,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
return willBind;
}
+ private void dump(IndentingPrintWriter pw) {
+ pw.printPair("context", mContext);
+ pw.printPair("userId", mUserId);
+ synchronized (mLock) {
+ pw.printPair("binding", mBinding);
+ pw.printPair("numberRequests", mPendingRequests.size());
+ }
+ }
+
private final class TextClassifierServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6f728fcf1f00..642f57814c61 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -92,7 +92,6 @@ 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;
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;
@@ -119,7 +118,6 @@ import static com.android.server.wm.WindowManagerService.logSurface;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -2065,9 +2063,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
layoutAndAssignWindowLayersIfNeeded();
}
- int taskIdFromPoint(int x, int y) {
+ /**
+ * Used to obtain task ID when user taps on coordinate (x, y) in this display, and outside
+ * current task in focus.
+ *
+ * This returns the task ID of the foremost task at (x, y) if the task is not home. Otherwise it
+ * returns -1.
+ *
+ * @param x horizontal coordinate of the tap position
+ * @param y vertical coordinate of the tap position
+ * @return the task ID if a non-home task is found; -1 if not
+ */
+ int taskForTapOutside(int x, int y) {
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+ if (stack.isActivityTypeHome()) {
+ // We skip not only home stack, but also everything behind home because user can't
+ // see them.
+ break;
+ }
final int taskId = stack.taskIdFromPoint(x, y);
if (taskId != -1) {
return taskId;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index b7e37b2fd47a..25148d15343a 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -88,7 +88,7 @@ class TaskPositioningController {
}
taskId = task.mTaskId;
} else {
- taskId = displayContent.taskIdFromPoint(x, y);
+ taskId = displayContent.taskForTapOutside(x, y);
}
}
if (taskId >= 0) {
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
index fc07aa1ecd17..9512f1be66ef 100644
--- a/services/net/java/android/net/ip/IpNeighborMonitor.java
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -40,7 +40,6 @@ import android.util.Log;
import com.android.internal.util.BitUtils;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.net.InetAddress;
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index cfcba3a84f51..40098c1532b1 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -32,7 +32,6 @@ import android.system.Os;
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
deleted file mode 100644
index 9de64f2cf211..000000000000
--- a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
+++ /dev/null
@@ -1,144 +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.server.am;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for exercising resizing bounds due to activity options.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
- private ActivityLaunchParamsModifier mModifier;
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
- private ActivityRecord mActivity;
-
- private LaunchParams mCurrent;
- private LaunchParams mResult;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mService = createActivityTaskManagerService();
- mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
- mCurrent = new LaunchParams();
- mResult = new LaunchParams();
-
-
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
- mActivity = new ActivityBuilder(mService).setTask(mTask).build();
- }
-
-
- @Test
- public void testSkippedInvocations() throws Exception {
- // No specified activity should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // No specified activity options should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // launch bounds specified should be ignored.
- final ActivityOptions options = ActivityOptions.makeBasic();
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Non-resizeable records should be ignored
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
- assertFalse(mActivity.isResizeable());
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // make record resizeable
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- assertTrue(mActivity.isResizeable());
-
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Does not support freeform
- mService.mSupportsFreeformWindowManagement = false;
- assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- mService.mSupportsFreeformWindowManagement = true;
- options.setLaunchBounds(new Rect());
- assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-
- // Invalid bounds
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- options.setLaunchBounds(new Rect(0, 0, -1, -1));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Valid bounds should cause the positioner to be applied.
- options.setLaunchBounds(new Rect(0, 0, 100, 100));
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- }
-
- @Test
- public void testBoundsExtraction() throws Exception {
- // Make activity resizeable and enable freeform mode.
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mService.mSupportsFreeformWindowManagement = true;
-
- ActivityOptions options = ActivityOptions.makeBasic();
- final Rect proposedBounds = new Rect(20, 30, 45, 40);
- options.setLaunchBounds(proposedBounds);
-
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, proposedBounds);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index f5b8f78cfd53..0d1302f78316 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -11,239 +11,1098 @@
* 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
+ * limitations under the License.
*/
package com.android.server.am;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
-import android.content.pm.ActivityInfo.WindowLayout;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.platform.test.annotations.Presubmit;
import android.view.Gravity;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.am.LaunchParamsController.LaunchParams;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Locale;
+
/**
- * Tests for exercising resizing task bounds.
+ * Tests for default task bounds.
*
* Build/Install/Run:
* atest FrameworksServicesTests:TaskLaunchParamsModifierTests
*/
-@MediumTest
+@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
+@FlakyTest(detail = "Confirm stable in post-submit before removing")
public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
- private final static int STACK_WIDTH = 100;
- private final static int STACK_HEIGHT = 200;
-
- private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
+ private ActivityRecord mActivity;
- private TaskLaunchParamsModifier mPositioner;
+ private TaskLaunchParamsModifier mTarget;
- private LaunchParamsController.LaunchParams mCurrent;
- private LaunchParamsController.LaunchParams mResult;
+ private LaunchParams mCurrent;
+ private LaunchParams mResult;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mStack.requestResize(STACK_BOUNDS);
+ setupActivityTaskManagerService();
+ mService.mSupportsFreeformWindowManagement = true;
+ when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
+
+ mActivity = new ActivityBuilder(mService).build();
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+
+ mTarget = new TaskLaunchParamsModifier(mSupervisor);
+
+ mCurrent = new LaunchParams();
+ mCurrent.reset();
+ mResult = new LaunchParams();
+ mResult.reset();
+ }
- // We must create the task after resizing to make sure it does not inherit the stack
- // dimensions on resize.
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ // =============================
+ // Display ID Related Tests
+ // =============================
+ @Test
+ public void testDefaultToPrimaryDisplay() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
- mPositioner = new TaskLaunchParamsModifier();
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
- mResult = new LaunchParamsController.LaunchParams();
- mCurrent = new LaunchParamsController.LaunchParams();
+ assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that the setup bounds are set as expected with the stack bounds set and the task
- * bounds still {@code null}.
- * @throws Exception
- */
@Test
- public void testInitialBounds() throws Exception {
- assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
- assertEquals(mTask.getOverrideBounds(), new Rect());
+ public void testUsesPreviousDisplayIdIfSet() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(display.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testLaunchNoWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
- null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
+ public void testUsesSourcesDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ ActivityRecord source = createSourceActivity(fullscreenDisplay);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, /* options */ null, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testlaunchEmptyWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
+ public void testUsesOptionsDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ ActivityRecord source = createSourceActivity(freeformDisplay);
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
- * according to specification.
- * @throws Exception
- */
+ // =====================================
+ // Launch Windowing Mode Related Tests
+ // =====================================
@Test
- public void testlaunchWindowLayoutGravity() throws Exception {
- // Unspecified gravity should be ignored
- testGravity(Gravity.NO_GRAVITY);
+ public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
- // Unsupported gravity should be ignored
- testGravity(Gravity.LEFT);
- testGravity(Gravity.RIGHT);
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
- // Test defaults for vertical gravities
- testGravity(Gravity.TOP);
- testGravity(Gravity.BOTTOM);
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
- // Test corners
- testGravity(Gravity.TOP | Gravity.LEFT);
- testGravity(Gravity.TOP | Gravity.RIGHT);
- testGravity(Gravity.BOTTOM | Gravity.LEFT);
- testGravity(Gravity.BOTTOM | Gravity.RIGHT);
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
}
- private void testGravity(int gravity) {
- try {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(gravity));
- } finally {
- mCurrent.reset();
- mResult.reset();
- }
+ @Test
+ public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithResizeableActivity() {
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesPreDApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesAppWithoutMultipleDensitySupport() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.flags = 0;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesUnresizeableApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFullscreenOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPostNApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ // ================================
+ // Launching Bounds Related Tests
+ // ===============================
+ @Test
+ public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ final Rect expected = new Rect(0, 0, 100, 100);
+ options.setLaunchBounds(expected);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(expected, mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.left);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.top);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ 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);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1920, mResult.mBounds.right);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1080, mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ 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);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidthFraction(0.0625f).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);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsWithResizeableActivity() {
+ final ActivityDisplay display = mSupervisor.getActivityDisplay(DEFAULT_DISPLAY);
+ display.setBounds(new Rect(0, 0, 1920, 1080));
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
+ }
+
+ @Test
+ public void testDefaultSizeSmallerThanBigScreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final int resultWidth = mResult.mBounds.width();
+ final int displayWidth = freeformDisplay.getBounds().width();
+ assertTrue("Result width " + resultWidth + " is not smaller than " + displayWidth,
+ resultWidth < displayWidth);
+
+ final int resultHeight = mResult.mBounds.height();
+ final int displayHeight = freeformDisplay.getBounds().height();
+ assertTrue("Result width " + resultHeight + " is not smaller than "
+ + displayHeight, resultHeight < displayHeight);
+ }
+
+ @Test
+ public void testDefaultFreeformSizeCenteredToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ 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);
+ assertEquals("Distance to top and bottom should be equal.",
+ mResult.mBounds.top - displayBounds.top,
+ displayBounds.bottom - mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testCascadesToSourceSizeForFreeform() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 412, 732);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
+ assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
+ assertTrue("Bounds should be centered at somewhere in the left half, but it's "
+ + "centerX is " + mResult.mBounds.centerX(),
+ mResult.mBounds.centerX() < displayBounds.centerX());
+ assertTrue("Bounds should be centered at somewhere in the top half, but it's "
+ + "centerY is " + mResult.mBounds.centerY(),
+ mResult.mBounds.centerY() < displayBounds.centerY());
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 200, 400);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_LargerThanDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.setTo(mSupervisor.getOverrideConfiguration());
+ overrideConfig.setLayoutDirection(new Locale("ar"));
+ mSupervisor.onConfigurationChanged(overrideConfig);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
}
- /**
- * Ensures that a task which causes a conflict with another task when positioned is adjusted as
- * expected.
- * @throws Exception
- */
- @Test
- public void testLaunchWindowCenterConflict() throws Exception {
- testConflict(Gravity.NO_GRAVITY);
- testConflict(Gravity.TOP);
- testConflict(Gravity.BOTTOM);
- testConflict(Gravity.TOP | Gravity.LEFT);
- testConflict(Gravity.TOP | Gravity.RIGHT);
- testConflict(Gravity.BOTTOM | Gravity.LEFT);
- testConflict(Gravity.BOTTOM | Gravity.RIGHT);
- }
-
- private void testConflict(int gravity) {
- final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
-
- // layout first task
- mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
-
- // Second task will be laid out on top of the first so starting bounds is the same.
- final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
-
- ActivityRecord activity = null;
- TaskRecord secondTask = null;
-
- // wrap with try/finally to ensure cleanup of activity/stack.
- try {
- // empty tasks are ignored in conflicts
- activity = new ActivityBuilder(mService).setTask(mTask).build();
-
- // Create secondary task
- secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-
- // layout second task
- assertEquals(RESULT_CONTINUE,
- mPositioner.onCalculate(secondTask, layout, null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
-
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
- || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
- mStack.getOverrideBounds()), 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP
- || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
- } else {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
- TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
- }
-
- assertEquals(mResult.mBounds, expectedBounds);
- } finally {
- // Remove task and activity to prevent influencing future tests
- if (activity != null) {
- mTask.removeActivity(activity);
- }
-
- if (secondTask != null) {
- mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
- }
+ @Test
+ public void testRespectsLayoutMinDimensions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setMinWidth(500).setMinHeight(800).build();
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(500, mResult.mBounds.width());
+ assertEquals(800, mResult.mBounds.height());
+ }
+
+ @Test
+ public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(100, 100, 500, 300));
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(200, 0, 400, 400), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(50, 50, 500, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(170, 50, 620, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(1720, 50, 1850, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(1600, 50, 1730, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(0, 0, 1800, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(120, 0, 1920, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1860, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1740, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1800, 1013));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(240, 67, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 67, 1800, 1020));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1680,
+ 953), mResult.mBounds);
+ }
+
+ 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.getConfiguration().densityDpi = DENSITY_DEFAULT;
+ return display;
+ }
+
+ private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+ }
+
+ private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ task.setBounds(bounds);
+ }
+
+ private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
+ if (expected != parentWindowingMode) {
+ assertEquals(expected, actual);
+ } else {
+ assertEquals(WINDOWING_MODE_UNDEFINED, actual);
}
}
- private Rect getDefaultBounds(int gravity) {
- final Rect bounds = new Rect();
- bounds.set(mStack.getOverrideBounds());
+ private static class WindowLayoutBuilder {
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private float mWidthFraction = -1f;
+ private float mHeightFraction = -1f;
+ private int mGravity = Gravity.NO_GRAVITY;
+ private int mMinWidth = -1;
+ private int mMinHeight = -1;
- final int verticalInset =
- TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
- final int horizontalInset =
- TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
+ private WindowLayoutBuilder setWidth(int width) {
+ mWidth = width;
+ return this;
+ }
+
+ private WindowLayoutBuilder setHeight(int height) {
+ mHeight = height;
+ return this;
+ }
- bounds.inset(horizontalInset, verticalInset);
+ private WindowLayoutBuilder setWidthFraction(float widthFraction) {
+ mWidthFraction = widthFraction;
+ return this;
+ }
+
+ private WindowLayoutBuilder setHeightFraction(float heightFraction) {
+ mHeightFraction = heightFraction;
+ return this;
+ }
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP) {
- bounds.offsetTo(0, 0);
- } else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
- } else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- bounds.offsetTo(0, verticalInset * 2);
+ private WindowLayoutBuilder setGravity(int gravity) {
+ mGravity = gravity;
+ return this;
}
- return bounds;
+ private WindowLayoutBuilder setMinWidth(int minWidth) {
+ mMinWidth = minWidth;
+ return this;
+ }
+
+ private WindowLayoutBuilder setMinHeight(int minHeight) {
+ mMinHeight = minHeight;
+ return this;
+ }
+
+ private ActivityInfo.WindowLayout build() {
+ return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction,
+ mGravity, mMinWidth, mMinHeight);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index cd0f385ce04e..0e9a63ce728b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -19,6 +19,8 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -68,7 +70,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
}
@Test
- public void testStackPositionChildAt() throws Exception {
+ public void testStackPositionChildAt() {
// Test that always-on-top stack can't be moved to position other than top.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
final TaskStack stack2 = createTaskStackOnDisplay(mDisplayContent);
@@ -78,8 +80,8 @@ public class TaskStackContainersTests extends WindowTestsBase {
final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stack2Pos);
- assertGreaterThan(stack2Pos, stack1Pos);
+ assertThat(pinnedStackPos).isGreaterThan(stack2Pos);
+ assertThat(stack2Pos).isGreaterThan(stack1Pos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
@@ -93,7 +95,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
}
@Test
- public void testStackPositionBelowPinnedStack() throws Exception {
+ public void testStackPositionBelowPinnedStack() {
// Test that no stack can be above pinned stack.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
@@ -101,7 +103,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stackPos);
+ assertThat(pinnedStackPos).isGreaterThan(stackPos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 70e4ce419e0a..cf67d786056c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -48,18 +48,17 @@ import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.WindowManager;
-import androidx.test.InstrumentationRegistry;
-
import com.android.server.AttributeCache;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import java.util.HashSet;
import java.util.LinkedList;
+import androidx.test.InstrumentationRegistry;
+
/**
* Common base class for window manager unit test classes.
*
@@ -194,14 +193,6 @@ class WindowTestsBase {
}
}
- /**
- * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
- * set-up (or null).
- */
- SurfaceBuilderFactory getSurfaceBuilderFactory() {
- return null;
- }
-
private WindowState createCommonWindow(WindowState parent, int type, String name) {
synchronized (sWm.mWindowMap) {
final WindowState win = createWindow(parent, type, name);
@@ -212,16 +203,6 @@ class WindowTestsBase {
}
}
- /** Asserts that the first entry is greater than the second entry. */
- void assertGreaterThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
- }
-
- /** Asserts that the first entry is greater than the second entry. */
- void assertLessThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
- }
-
/**
* Waits until the main handler for WM has processed all messages.
*/
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 8f9fb1b7d5ec..a610e6efda8c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -32,36 +32,35 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static com.google.common.truth.Truth.assertThat;
+
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.LinkedList;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for the {@link WindowLayersController} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ * atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
*/
@SmallTest
@FlakyTest(bugId = 74078662)
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class ZOrderingTests extends WindowTestsBase {
private class LayerRecordingTransaction extends SurfaceControl.Transaction {
- HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap();
- HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap();
+ HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
+ HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
@Override
public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
@@ -86,11 +85,11 @@ public class ZOrderingTests extends WindowTestsBase {
private SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
- };
+ }
// We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
// such that we can keep track of the parents of Surfaces as they are constructed.
- private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap();
+ private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
private class HierarchyRecorder extends SurfaceControl.Builder {
SurfaceControl mPendingParent;
@@ -109,13 +108,13 @@ public class ZOrderingTests extends WindowTestsBase {
mPendingParent = null;
return sc;
}
- };
+ }
class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
public SurfaceControl.Builder make(SurfaceSession s) {
return new HierarchyRecorder(s);
}
- };
+ }
private LayerRecordingTransaction mTransaction;
@@ -136,7 +135,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
- LinkedList<SurfaceControl> p = new LinkedList();
+ LinkedList<SurfaceControl> p = new LinkedList<>();
SurfaceControl current = sc;
do {
p.addLast(current);
@@ -153,7 +152,7 @@ public class ZOrderingTests extends WindowTestsBase {
void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
- SurfaceControl right) throws Exception {
+ SurfaceControl right) {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
@@ -168,16 +167,15 @@ public class ZOrderingTests extends WindowTestsBase {
}
if (rightTop == null) { // right is the parent of left.
- assertGreaterThan(t.getLayer(leftTop), 0);
+ assertThat(t.getLayer(leftTop)).isGreaterThan(0);
} else if (leftTop == null) { // left is the parent of right.
- assertGreaterThan(0, t.getLayer(rightTop));
+ assertThat(t.getLayer(rightTop)).isLessThan(0);
} else {
- assertGreaterThan(t.getLayer(leftTop),
- t.getLayer(rightTop));
+ assertThat(t.getLayer(leftTop)).isGreaterThan(t.getLayer(rightTop));
}
}
- void assertWindowHigher(WindowState left, WindowState right) throws Exception {
+ void assertWindowHigher(WindowState left, WindowState right) {
assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
}
@@ -186,7 +184,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithNoTarget() {
sWm.mInputMethodTarget = null;
mDisplayContent.assignChildLayers(mTransaction);
@@ -203,7 +201,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
sWm.mInputMethodTarget = imeAppTarget;
@@ -222,7 +220,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
@@ -248,7 +246,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
@@ -271,7 +269,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
mDisplayContent, "imeSystemOverlayTarget",
true /* ownerCanAddInternalSystemWindow */);
@@ -298,7 +296,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForStatusBarImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForStatusBarImeTarget() {
sWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
@@ -312,7 +310,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testStackLayers() throws Exception {
+ public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
@@ -342,7 +340,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForSysUiPanels() throws Exception {
+ public void testAssignWindowLayers_ForSysUiPanels() {
final WindowState navBarPanel =
createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
final WindowState statusBarPanel =
@@ -359,7 +357,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() throws Exception {
+ public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() {
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side.
@@ -376,7 +374,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testDockedDividerPosition() throws Exception {
+ public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 08bc9bcc4003..daa09f574651 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -397,7 +397,19 @@ public final class Call {
public static final int PROPERTY_WIFI = 0x00000008;
/**
- * Call is using high definition audio.
+ * When set, the UI should indicate to the user that a call is using high definition
+ * audio.
+ * <p>
+ * The underlying {@link ConnectionService} is responsible for reporting this
+ * property. It is important to note that this property is not intended to report the
+ * actual audio codec being used for a Call, but whether the call should be indicated
+ * to the user as high definition.
+ * <p>
+ * The Android Telephony stack reports this property for calls based on a number
+ * of factors, including which audio codec is used and whether a call is using an HD
+ * codec end-to-end. Some mobile operators choose to suppress display of an HD indication,
+ * and in these cases this property will not be set for a call even if the underlying audio
+ * codec is in fact "high definition".
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4846092286ba..8454d12ac317 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3289,7 +3289,6 @@ public final class Telephony {
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
return values;
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index c3931557feb3..b312f8478413 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -95,6 +95,13 @@ public class NetworkRegistrationState implements Parcelable {
@RegState
private final int mRegState;
+ /**
+ * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
+ * from resource overlay or carrier config.
+ */
+ @ServiceState.RoamingType
+ private int mRoamingType;
+
private final int mAccessNetworkTechnology;
private final int mRejectCause;
@@ -140,6 +147,8 @@ public class NetworkRegistrationState implements Parcelable {
mDomain = domain;
mTransportType = transportType;
mRegState = regState;
+ mRoamingType = (regState == REG_STATE_ROAMING)
+ ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
mAccessNetworkTechnology = accessNetworkTechnology;
mRejectCause = rejectCause;
mAvailableServices = availableServices;
@@ -182,6 +191,7 @@ public class NetworkRegistrationState implements Parcelable {
mDomain = source.readInt();
mTransportType = source.readInt();
mRegState = source.readInt();
+ mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
mEmergencyOnly = source.readBoolean();
@@ -211,6 +221,31 @@ public class NetworkRegistrationState implements Parcelable {
}
/**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
+ public boolean isRoaming() {
+ return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
+ }
+
+ /**
+ * Set {@link ServiceState.RoamingType roaming type}. This could override
+ * roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public void setRoamingType(@ServiceState.RoamingType int roamingType) {
+ mRoamingType = roamingType;
+ }
+
+ /**
+ * @return {@link ServiceState.RoamingType roaming type}. This could return
+ * overridden roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public @ServiceState.RoamingType int getRoamingType() {
+ return mRoamingType;
+ }
+
+ /**
* @return Whether emergency is enabled.
*/
public boolean isEmergencyEnabled() { return mEmergencyOnly; }
@@ -280,6 +315,7 @@ public class NetworkRegistrationState implements Parcelable {
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
.append("transportType=").append(mTransportType)
.append(" regState=").append(regStateToString(mRegState))
+ .append(" roamingType=").append(mRoamingType)
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
@@ -293,9 +329,9 @@ public class NetworkRegistrationState implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegState, mAccessNetworkTechnology,
- mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity,
- mVoiceSpecificStates, mDataSpecificStates);
+ return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+ mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
+ mCellIdentity, mVoiceSpecificStates, mDataSpecificStates);
}
@Override
@@ -310,6 +346,7 @@ public class NetworkRegistrationState implements Parcelable {
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegState == other.mRegState
+ && mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
@@ -325,6 +362,7 @@ public class NetworkRegistrationState implements Parcelable {
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegState);
+ dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
dest.writeBoolean(mEmergencyOnly);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 60e103aa62e0..e0ec2c50ab5b 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -200,6 +201,15 @@ public class ServiceState implements Parcelable {
private int mVoiceRegState = STATE_OUT_OF_SERVICE;
private int mDataRegState = STATE_OUT_OF_SERVICE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ROAMING_TYPE_" }, value = {
+ ROAMING_TYPE_NOT_ROAMING,
+ ROAMING_TYPE_UNKNOWN,
+ ROAMING_TYPE_DOMESTIC,
+ ROAMING_TYPE_INTERNATIONAL
+ })
+ public @interface RoamingType {}
/**
* Roaming type
* HOME : in home network
@@ -230,8 +240,6 @@ public class ServiceState implements Parcelable {
*/
public static final int UNKNOWN_ID = -1;
- private int mVoiceRoamingType;
- private int mDataRoamingType;
private String mVoiceOperatorAlphaLong;
private String mVoiceOperatorAlphaShort;
private String mVoiceOperatorNumeric;
@@ -261,8 +269,6 @@ public class ServiceState implements Parcelable {
@UnsupportedAppUsage
private int mCdmaEriIconMode;
- private boolean mIsDataRoamingFromRegistration;
-
@UnsupportedAppUsage
private boolean mIsUsingCarrierAggregation;
@@ -334,8 +340,6 @@ public class ServiceState implements Parcelable {
protected void copyFrom(ServiceState s) {
mVoiceRegState = s.mVoiceRegState;
mDataRegState = s.mDataRegState;
- mVoiceRoamingType = s.mVoiceRoamingType;
- mDataRoamingType = s.mDataRoamingType;
mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
@@ -353,7 +357,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
@@ -369,8 +372,6 @@ public class ServiceState implements Parcelable {
public ServiceState(Parcel in) {
mVoiceRegState = in.readInt();
mDataRegState = in.readInt();
- mVoiceRoamingType = in.readInt();
- mDataRoamingType = in.readInt();
mVoiceOperatorAlphaLong = in.readString();
mVoiceOperatorAlphaShort = in.readString();
mVoiceOperatorNumeric = in.readString();
@@ -388,7 +389,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsDataRoamingFromRegistration = in.readInt() != 0;
mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationStates = new ArrayList<>();
@@ -400,8 +400,6 @@ public class ServiceState implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mVoiceRegState);
out.writeInt(mDataRegState);
- out.writeInt(mVoiceRoamingType);
- out.writeInt(mDataRoamingType);
out.writeString(mVoiceOperatorAlphaLong);
out.writeString(mVoiceOperatorAlphaShort);
out.writeString(mVoiceOperatorNumeric);
@@ -419,7 +417,6 @@ public class ServiceState implements Parcelable {
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationStates);
@@ -537,17 +534,21 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
public boolean getVoiceRoaming() {
- return mVoiceRoamingType != ROAMING_TYPE_NOT_ROAMING;
+ return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
-
/**
* Get current voice network roaming type
* @return roaming type
* @hide
*/
@UnsupportedAppUsage
- public int getVoiceRoamingType() {
- return mVoiceRoamingType;
+ public @RoamingType int getVoiceRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -557,19 +558,7 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
public boolean getDataRoaming() {
- return mDataRoamingType != ROAMING_TYPE_NOT_ROAMING;
- }
-
- /**
- * Set whether data network registration state is roaming
- *
- * This should only be set to the roaming value received
- * once the data registration phase has completed.
- * @hide
- */
- @UnsupportedAppUsage
- public void setDataRoamingFromRegistration(boolean dataRoaming) {
- mIsDataRoamingFromRegistration = dataRoaming;
+ return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -578,7 +567,12 @@ public class ServiceState implements Parcelable {
* @hide
*/
public boolean getDataRoamingFromRegistration() {
- return mIsDataRoamingFromRegistration;
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+ }
+ return false;
}
/**
@@ -587,8 +581,13 @@ public class ServiceState implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- public int getDataRoamingType() {
- return mDataRoamingType;
+ public @RoamingType int getDataRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -761,8 +760,6 @@ public class ServiceState implements Parcelable {
return Objects.hash(
mVoiceRegState,
mDataRegState,
- mVoiceRoamingType,
- mDataRoamingType,
mChannelNumber,
mCellBandwidths,
mVoiceOperatorAlphaLong,
@@ -782,7 +779,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsDataRoamingFromRegistration,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationStates);
@@ -796,8 +792,6 @@ public class ServiceState implements Parcelable {
return (mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
- && mVoiceRoamingType == s.mVoiceRoamingType
- && mDataRoamingType == s.mDataRoamingType
&& mChannelNumber == s.mChannelNumber
&& Arrays.equals(mCellBandwidths, s.mCellBandwidths)
&& equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
@@ -815,7 +809,6 @@ public class ServiceState implements Parcelable {
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
&& mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
s.mNetworkRegistrationStates != null &&
@@ -935,8 +928,6 @@ public class ServiceState implements Parcelable {
.append(", mChannelNumber=").append(mChannelNumber)
.append(", duplexMode()=").append(getDuplexMode())
.append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
- .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
- .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
.append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
.append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
.append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
@@ -953,7 +944,6 @@ public class ServiceState implements Parcelable {
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
.append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
@@ -964,8 +954,6 @@ public class ServiceState implements Parcelable {
if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
mVoiceRegState = state;
mDataRegState = state;
- mVoiceRoamingType = ROAMING_TYPE_NOT_ROAMING;
- mDataRoamingType = ROAMING_TYPE_NOT_ROAMING;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -985,7 +973,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsDataRoamingFromRegistration = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
mNetworkRegistrationStates = new ArrayList<>();
@@ -1031,32 +1018,50 @@ public class ServiceState implements Parcelable {
}
public void setRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
- mDataRoamingType = mVoiceRoamingType;
+ setVoiceRoaming(roaming);
+ setDataRoaming(roaming);
}
/** @hide */
@UnsupportedAppUsage
public void setVoiceRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setVoiceRoamingType(roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setVoiceRoamingType(int type) {
- mVoiceRoamingType = type;
+ public void setVoiceRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/** @hide */
@UnsupportedAppUsage
public void setDataRoaming(boolean dataRoaming) {
- mDataRoamingType = (dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setDataRoamingType(dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setDataRoamingType(int type) {
- mDataRoamingType = type;
+ public void setDataRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/**
@@ -1168,30 +1173,10 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
private void setFromNotifierBundle(Bundle m) {
- mVoiceRegState = m.getInt("voiceRegState");
- mDataRegState = m.getInt("dataRegState");
- mVoiceRoamingType = m.getInt("voiceRoamingType");
- mDataRoamingType = m.getInt("dataRoamingType");
- mVoiceOperatorAlphaLong = m.getString("operator-alpha-long");
- mVoiceOperatorAlphaShort = m.getString("operator-alpha-short");
- mVoiceOperatorNumeric = m.getString("operator-numeric");
- mDataOperatorAlphaLong = m.getString("data-operator-alpha-long");
- mDataOperatorAlphaShort = m.getString("data-operator-alpha-short");
- mDataOperatorNumeric = m.getString("data-operator-numeric");
- mIsManualNetworkSelection = m.getBoolean("manual");
- mRilVoiceRadioTechnology = m.getInt("radioTechnology");
- mRilDataRadioTechnology = m.getInt("dataRadioTechnology");
- mCssIndicator = m.getBoolean("cssIndicator");
- mNetworkId = m.getInt("networkId");
- mSystemId = m.getInt("systemId");
- mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
- mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
- mIsEmergencyOnly = m.getBoolean("emergencyOnly");
- mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
- mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
- mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
- mChannelNumber = m.getInt("ChannelNumber");
- mCellBandwidths = m.getIntArray("CellBandwidths");
+ ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE);
+ if (ssFromBundle != null) {
+ copyFrom(ssFromBundle);
+ }
}
/**
@@ -1202,10 +1187,13 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
public void fillInNotifierBundle(Bundle m) {
+ m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
+ // serviceState already consists of below entries.
+ // for backward compatibility, we continue fill in below entries.
m.putInt("voiceRegState", mVoiceRegState);
m.putInt("dataRegState", mDataRegState);
- m.putInt("voiceRoamingType", mVoiceRoamingType);
- m.putInt("dataRoamingType", mDataRoamingType);
+ m.putInt("dataRoamingType", getDataRoamingType());
+ m.putInt("voiceRoamingType", getVoiceRoamingType());
m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
m.putString("operator-numeric", mVoiceOperatorNumeric);
@@ -1221,7 +1209,7 @@ public class ServiceState implements Parcelable {
m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
- m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+ m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a2647077d51a..f85069385f3c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,12 +32,14 @@ import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.INetworkPolicyManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
@@ -116,6 +118,52 @@ public class SubscriptionManager {
@UnsupportedAppUsage
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * Generates a content {@link Uri} used to receive updates on simInfo change
+ * on the given subscriptionId
+ * @param subscriptionId the subscriptionId to receive updates on
+ * @return the Uri used to observe carrier identity changes
+ * @hide
+ */
+ public static Uri getUriForSubscriptionId(int subscriptionId) {
+ return Uri.withAppendedPath(CONTENT_URI, String.valueOf(subscriptionId));
+ }
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc enabled user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
+
+ /**
+ * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "enhanced_4g");
+
+
/**
* TelephonyProvider unique key column name is the subscription id.
* <P>Type: TEXT (String)</P>
@@ -1603,7 +1651,7 @@ public class SubscriptionManager {
* Check if the subscription ID is usable.
*
* A usable subscription ID has a valid value except some special values such as
- * {@link DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
+ * {@link #DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
*
* @param subscriptionId the subscription ID
* @return {@code true} if the subscription ID is usable; {@code false} otherwise.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1106a49d341f..fca14c823751 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,6 +60,7 @@ import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -5402,7 +5403,7 @@ public class TelephonyManager {
@UnsupportedAppUsage
public static String getTelephonyProperty(String property, String defaultVal) {
String propVal = SystemProperties.get(property);
- return propVal == null ? defaultVal : propVal;
+ return TextUtils.isEmpty(propVal) ? defaultVal : propVal;
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3a263504a2ec..cb8269efe443 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -420,6 +420,7 @@ public interface RILConstants {
int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 201;
int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 202;
int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203;
+ int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index dac7e04be07a..9730ebc57fcf 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -32,6 +32,7 @@ import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -43,6 +44,10 @@ public final class TelephonyPermissions {
private static final boolean DBG = false;
+ // When set to true this flag will treat all apps that fail the device identifier check as
+ // though they are targeting pre-Q and return dummy data instead of throwing a SecurityException
+ private static final boolean RELAX_DEVICE_IDENTIFIER_CHECK = true;
+
private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
@@ -275,31 +280,41 @@ public final class TelephonyPermissions {
*/
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
- if (callingPackage != null) {
- try {
- // if the target SDK is pre-Q then check if the calling package would have
- // previously had access to device identifiers.
- ApplicationInfo callingPackageInfo = context.getPackageManager().getApplicationInfo(
- callingPackage, 0);
- if (callingPackageInfo != null
- && callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
- if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid,
- uid) == PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- if (SubscriptionManager.isValidSubscriptionId(subId)
- && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return false;
+ // if the device identifier check is relaxed then just return false to return dummy data to
+ // the caller instead of throwing a SecurityException for apps targeting Q+.
+ if (RELAX_DEVICE_IDENTIFIER_CHECK) {
+ Log.wtf(LOG_TAG,
+ "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
+ return false;
+ } else {
+ if (callingPackage != null) {
+ try {
+ // if the target SDK is pre-Q then check if the calling package would have
+ // previously had access to device identifiers.
+ ApplicationInfo callingPackageInfo =
+ context.getPackageManager().getApplicationInfo(
+ callingPackage, 0);
+ if (callingPackageInfo != null
+ && callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE,
+ pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return false;
+ }
}
+ } catch (PackageManager.NameNotFoundException e) {
+ // If the application info for the calling package could not be found then
+ // default to throwing the SecurityException.
}
- } catch (PackageManager.NameNotFoundException e) {
- // If the application info for the calling package could not be found then default
- // to throwing the SecurityException.
}
+ throw new SecurityException(message + ": The user " + uid + " does not have the "
+ + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
}
- throw new SecurityException(message + ": The user " + uid + " does not have the "
- + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
}
/**
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index c225e170c377..a6c21db16846 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -7,7 +7,6 @@ LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- conscrypt \
android.test.base \
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 954f1ed3fb72..3ea17552ea7c 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -46,7 +46,7 @@ class IApkSerializer {
IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) = 0;
+ IArchiveWriter* writer, uint32_t compression_flags) = 0;
virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
virtual bool SerializeFile(FileReference* file, IArchiveWriter* writer) = 0;
@@ -59,7 +59,10 @@ class IApkSerializer {
bool ConvertApk(IAaptContext* context, unique_ptr<LoadedApk> apk, IApkSerializer* serializer,
IArchiveWriter* writer) {
- if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+ io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
+ if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer,
+ (manifest != nullptr && manifest->WasCompressed())
+ ? ArchiveEntry::kCompress : 0u)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return false;
@@ -133,7 +136,7 @@ class BinaryApkSerializer : public IApkSerializer {
: IApkSerializer(context, source), tableFlattenerOptions_(options) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.use_utf16 = utf16;
@@ -144,8 +147,7 @@ class BinaryApkSerializer : public IApkSerializer {
}
io::BigBufferInputStream input_stream(&buffer);
- return io::CopyInputStreamToArchive(context_, &input_stream, path, ArchiveEntry::kCompress,
- writer);
+ return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -186,7 +188,8 @@ class BinaryApkSerializer : public IApkSerializer {
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to binary XML: " << *file->path);
return false;
@@ -216,10 +219,10 @@ class ProtoApkSerializer : public IApkSerializer {
: IApkSerializer(context, source) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
pb::XmlNode pb_node;
SerializeXmlResourceToPb(*xml, &pb_node);
- return io::CopyProtoToArchive(context_, &pb_node, path, ArchiveEntry::kCompress, writer);
+ return io::CopyProtoToArchive(context_, &pb_node, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -246,7 +249,8 @@ class ProtoApkSerializer : public IApkSerializer {
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to proto XML: " << *file->path);
return false;
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 4245700ed90d..d1f42f8b398e 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -251,7 +251,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
}
atomDecl->fields.push_back(atField);
- if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
+ if (field->options().GetExtension(os::statsd::state_field_option).option() ==
os::statsd::StateField::PRIMARY) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
@@ -261,7 +261,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
atomDecl->primaryFields.push_back(it->first);
}
- if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
+ if (field->options().GetExtension(os::statsd::state_field_option).option() ==
os::statsd::StateField::EXCLUSIVE) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 264a865e3b39..f6359748a27e 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -127,33 +127,33 @@ message GoodStateAtoms {
// The atom has only primary field but no exclusive state field.
message BadStateAtom1 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
}
// Only primative types can be annotated.
message BadStateAtom2 {
repeated android.os.statsd.AttributionNode attribution = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// Having 2 exclusive state field in the atom means the atom is badly designed.
// E.g., putting bluetooth state and wifi state in the same atom.
message BadStateAtom3 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
optional int32 state2 = 3
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
message GoodStateAtom1 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// Atoms can have exclusive state field, but no primary field. That means
@@ -161,16 +161,16 @@ message GoodStateAtom1 {
message GoodStateAtom2 {
optional int32 uid = 1;
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// We can have more than one primary fields. That means their combination is a
// primary key.
message GoodStateAtom3 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 tid = 2
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 3
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
} \ No newline at end of file