summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp5
-rw-r--r--api/current.txt54
-rw-r--r--api/system-current.txt6
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java68
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java2
-rw-r--r--core/java/android/content/pm/PermissionInfo.java14
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java33
-rw-r--r--core/java/android/hardware/hdmi/HdmiUtils.java81
-rw-r--r--core/java/android/net/IpPrefixParcelable.aidl22
-rw-r--r--core/java/android/net/LinkAddressParcelable.aidl24
-rw-r--r--core/java/android/net/LinkPropertiesParcelable.aidl39
-rw-r--r--core/java/android/net/ProxyInfoParcelable.aidl24
-rw-r--r--core/java/android/net/RouteInfoParcelable.aidl26
-rw-r--r--core/java/android/os/GraphicsEnvironment.java15
-rw-r--r--core/java/android/provider/DeviceConfig.java9
-rw-r--r--core/java/android/provider/Settings.java24
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java6
-rw-r--r--core/java/android/webkit/WebView.java80
-rw-r--r--core/java/android/webkit/WebViewProvider.java9
-rw-r--r--core/java/android/webkit/WebViewRenderer.java45
-rw-r--r--core/java/android/webkit/WebViewRendererClient.java77
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java82
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--media/Android.bp17
-rw-r--r--media/java/android/media/MediaCodecInfo.java69
-rw-r--r--media/java/android/media/MediaFormat.java1
-rw-r--r--media/java/android/media/Session2Token.java7
-rw-r--r--media/java/android/media/session/MediaSessionProviderService.java35
-rw-r--r--media/packages/MediaCore/Android.bp21
-rw-r--r--media/packages/MediaCore/AndroidManifest.xml32
-rw-r--r--media/packages/MediaCore/res/values/strings.xml21
-rw-r--r--media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java37
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java7
-rw-r--r--packages/SettingsProvider/test/AndroidManifest.xml2
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/bubble_clock.xml10
-rw-r--r--packages/SystemUI/res-keyguard/layout/digital_clock.xml11
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml12
-rw-r--r--packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml10
-rw-r--r--packages/SystemUI/res-keyguard/layout/text_clock.xml29
-rw-r--r--packages/SystemUI/res/layout/global_actions_wrapped.xml1
-rw-r--r--packages/SystemUI/res/values/ids.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/MultiListLayout.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java117
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java241
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java19
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java2
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java8
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java8
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java1
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java46
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java86
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java258
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java7
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java55
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java20
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java3
-rw-r--r--services/core/java/com/android/server/wm/Session.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskTapPointerEventListener.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java17
-rw-r--r--services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java222
-rw-r--r--services/net/java/android/net/shared/ParcelableUtil.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java134
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java146
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java59
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java8
-rw-r--r--telephony/java/com/android/internal/telephony/DctConstants.java3
-rw-r--r--tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java193
94 files changed, 2896 insertions, 464 deletions
diff --git a/Android.bp b/Android.bp
index 834c9b08b07b..54b6619db25e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -889,7 +889,12 @@ aidl_interface {
"core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
+ "core/java/android/net/IpPrefixParcelable.aidl",
+ "core/java/android/net/LinkAddressParcelable.aidl",
+ "core/java/android/net/LinkPropertiesParcelable.aidl",
"core/java/android/net/PrivateDnsConfigParcel.aidl",
+ "core/java/android/net/ProxyInfoParcelable.aidl",
+ "core/java/android/net/RouteInfoParcelable.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
diff --git a/api/current.txt b/api/current.txt
index 40264045d4d7..cea404f6f98c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6784,9 +6784,11 @@ package android.app.admin {
method public void wipeData(int);
method public void wipeData(int, java.lang.CharSequence);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+ field public static final java.lang.String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
+ field public static final java.lang.String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6829,12 +6831,15 @@ package android.app.admin {
field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
field public static final deprecated java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
+ field public static final java.lang.String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+ field public static final java.lang.String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
+ field public static final java.lang.String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -6911,6 +6916,9 @@ package android.app.admin {
field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
+ field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
+ field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+ field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -24365,6 +24373,33 @@ package android.media {
field public static final int AACObjectSSR = 3; // 0x3
field public static final int AACObjectScalable = 6; // 0x6
field public static final int AACObjectXHE = 42; // 0x2a
+ field public static final int AV1Level2 = 1; // 0x1
+ field public static final int AV1Level21 = 2; // 0x2
+ field public static final int AV1Level22 = 4; // 0x4
+ field public static final int AV1Level23 = 8; // 0x8
+ field public static final int AV1Level3 = 16; // 0x10
+ field public static final int AV1Level31 = 32; // 0x20
+ field public static final int AV1Level32 = 64; // 0x40
+ field public static final int AV1Level33 = 128; // 0x80
+ field public static final int AV1Level4 = 256; // 0x100
+ field public static final int AV1Level41 = 512; // 0x200
+ field public static final int AV1Level42 = 1024; // 0x400
+ field public static final int AV1Level43 = 2048; // 0x800
+ field public static final int AV1Level5 = 4096; // 0x1000
+ field public static final int AV1Level51 = 8192; // 0x2000
+ field public static final int AV1Level52 = 16384; // 0x4000
+ field public static final int AV1Level53 = 32768; // 0x8000
+ field public static final int AV1Level6 = 65536; // 0x10000
+ field public static final int AV1Level61 = 131072; // 0x20000
+ field public static final int AV1Level62 = 262144; // 0x40000
+ field public static final int AV1Level63 = 524288; // 0x80000
+ field public static final int AV1Level7 = 1048576; // 0x100000
+ field public static final int AV1Level71 = 2097152; // 0x200000
+ field public static final int AV1Level72 = 4194304; // 0x400000
+ field public static final int AV1Level73 = 8388608; // 0x800000
+ field public static final int AV1Profile0 = 1; // 0x1
+ field public static final int AV1Profile1 = 2; // 0x2
+ field public static final int AV1Profile2 = 4; // 0x4
field public static final int AVCLevel1 = 1; // 0x1
field public static final int AVCLevel11 = 4; // 0x4
field public static final int AVCLevel12 = 8; // 0x8
@@ -24382,6 +24417,9 @@ package android.media {
field public static final int AVCLevel5 = 16384; // 0x4000
field public static final int AVCLevel51 = 32768; // 0x8000
field public static final int AVCLevel52 = 65536; // 0x10000
+ field public static final int AVCLevel6 = 131072; // 0x20000
+ field public static final int AVCLevel61 = 262144; // 0x40000
+ field public static final int AVCLevel62 = 524288; // 0x80000
field public static final int AVCProfileBaseline = 1; // 0x1
field public static final int AVCProfileConstrainedBaseline = 65536; // 0x10000
field public static final int AVCProfileConstrainedHigh = 524288; // 0x80000
@@ -25002,6 +25040,7 @@ package android.media {
field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
+ field public static final java.lang.String MIMETYPE_VIDEO_AV1 = "video/av01";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
@@ -41739,6 +41778,7 @@ package android.service.voice {
field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
+ field public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 128; // 0x80
field public static final int SHOW_SOURCE_NOTIFICATION = 64; // 0x40
field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20
field public static final int SHOW_WITH_ASSIST = 1; // 0x1
@@ -54244,6 +54284,8 @@ package android.webkit {
method public static java.lang.ClassLoader getWebViewClassLoader();
method public android.webkit.WebViewClient getWebViewClient();
method public android.os.Looper getWebViewLooper();
+ method public android.webkit.WebViewRenderer getWebViewRenderer();
+ method public android.webkit.WebViewRendererClient getWebViewRendererClient();
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
@@ -54293,6 +54335,8 @@ package android.webkit {
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
method public void setWebViewClient(android.webkit.WebViewClient);
+ method public void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
+ method public void setWebViewRendererClient(android.webkit.WebViewRendererClient);
method public deprecated boolean shouldDelayChildPressedState();
method public deprecated boolean showFindDialog(java.lang.String, boolean);
method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
@@ -54408,6 +54452,16 @@ package android.webkit {
method public android.webkit.WebView getWebView();
}
+ public abstract class WebViewRenderer {
+ method public abstract boolean terminate();
+ }
+
+ public abstract class WebViewRendererClient {
+ ctor public WebViewRendererClient();
+ method public abstract void onRendererResponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+ method public abstract void onRendererUnresponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+ }
+
}
package android.widget {
diff --git a/api/system-current.txt b/api/system-current.txt
index acbc2a72241f..7ea7afbb8d20 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -128,6 +128,7 @@ package android {
field public static final java.lang.String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
+ field public static final java.lang.String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
@@ -184,6 +185,7 @@ package android {
field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
+ field public static final java.lang.String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -1559,6 +1561,7 @@ package android.content.pm {
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int FLAG_REMOVED = 2; // 0x2
+ field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
@@ -8500,6 +8503,8 @@ package android.webkit {
method public abstract int getVisibleTitleHeight();
method public abstract android.webkit.WebChromeClient getWebChromeClient();
method public abstract android.webkit.WebViewClient getWebViewClient();
+ method public abstract android.webkit.WebViewRenderer getWebViewRenderer();
+ method public abstract android.webkit.WebViewRendererClient getWebViewRendererClient();
method public abstract android.view.View getZoomControls();
method public abstract void goBack();
method public abstract void goBackOrForward(int);
@@ -8549,6 +8554,7 @@ package android.webkit {
method public abstract void setVerticalScrollbarOverlay(boolean);
method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
method public abstract void setWebViewClient(android.webkit.WebViewClient);
+ method public abstract void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
method public abstract boolean showFindDialog(java.lang.String, boolean);
method public abstract void stopLoading();
method public abstract boolean zoomBy(float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 6ddb341191cb..846442dbe031 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -420,6 +420,7 @@ package android.content.pm {
}
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9247486dff40..6d7c547f7cf1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2168,6 +2168,74 @@ public class DevicePolicyManager {
public @interface SetPrivateDnsModeResultConstants {}
/**
+ * Activity action: Starts the administrator to get the mode for the provisioning.
+ * This intent may contain the following extras:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_IMEI}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SERIAL_NUMBER}</li>
+ * </ul>
+ *
+ * <p>The target activity should return one of the following values in
+ * {@link #EXTRA_PROVISIONING_MODE} as result:
+ * <ul>
+ * <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+ * <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+ * <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+ * </ul>
+ *
+ * <p>The target activity may also return the account that needs to be migrated from primary
+ * user to managed profile in case of a profile owner provisioning in
+ * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} as result.
+ */
+ public static final String ACTION_GET_PROVISIONING_MODE =
+ "android.app.action.GET_PROVISIONING_MODE";
+
+ /**
+ * A string extra holding the IMEI (International Mobile Equipment Identity) of the device.
+ */
+ public static final String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
+
+ /**
+ * A string extra holding the serial number of the device.
+ */
+ public static final String EXTRA_PROVISIONING_SERIAL_NUMBER =
+ "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+
+ /**
+ * An intent extra holding the provisioning mode returned by the administrator.
+ * The value for this extra should be one of the following:
+ * <ul>
+ * <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+ * <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+ * <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+ * </ul>
+ */
+ public static final String EXTRA_PROVISIONING_MODE =
+ "android.app.extra.PROVISIONING_MODE";
+
+ /**
+ * The provisioning mode for fully managed device.
+ */
+ public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
+
+ /**
+ * The provisioning mode for managed profile.
+ */
+ public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
+
+ /**
+ * The provisioning mode for managed profile on a fully managed device.
+ */
+ public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3;
+
+ /**
+ * Activity action: Starts the administrator to show policy compliance for the provisioning.
+ */
+ public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
+ "android.app.action.ADMIN_POLICY_COMPLIANCE";
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 45b5dcac6cc0..359adbdb6e24 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -55,6 +55,7 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_PERMISSION_CONTROLLER = 6;
public static final int PACKAGE_WELLBEING = 7;
public static final int PACKAGE_DOCUMENTER = 8;
+ public static final int PACKAGE_CONFIGURATOR = 9;
@IntDef(value = {
PACKAGE_SYSTEM,
PACKAGE_SETUP_WIZARD,
@@ -65,6 +66,7 @@ public abstract class PackageManagerInternal {
PACKAGE_PERMISSION_CONTROLLER,
PACKAGE_WELLBEING,
PACKAGE_DOCUMENTER,
+ PACKAGE_CONFIGURATOR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index a3395ac9fd13..5d2cf0a7d101 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -203,6 +203,16 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@TestApi
public static final int PROTECTION_FLAG_DOCUMENTER = 0x40000;
+ /**
+ * Additional flag for {@link #protectionLevel}, corresponding to the
+ * {@code configurator} value of {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000;
+
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
@@ -222,6 +232,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
PROTECTION_FLAG_WELLBEING,
PROTECTION_FLAG_DOCUMENTER,
+ PROTECTION_FLAG_CONFIGURATOR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -417,6 +428,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
protLevel += "|documenter";
}
+ if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
+ protLevel += "|configurator";
+ }
return protLevel;
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index a7734f544607..a98b31ad6a5e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -55,6 +55,10 @@ public final class HdmiControlManager {
@Nullable private final IHdmiControlService mService;
+ private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+ private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
/**
* Broadcast Action: Display OSD message.
* <p>Send when the service has a message to display on screen for events
@@ -505,14 +509,41 @@ public final class HdmiControlManager {
* @hide
*/
public int getPhysicalAddress() {
+ if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
+ return mPhysicalAddress;
+ }
try {
- return mService.getPhysicalAddress();
+ mPhysicalAddress = mService.getPhysicalAddress();
+ return mPhysicalAddress;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
+ * Check if the target device is connected to the current device. The
+ * API also returns true if the current device is the target.
+ *
+ * @param targetDevice {@link HdmiDeviceInfo} of the target device.
+ * @return true if {@code device} is directly or indirectly connected to the
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+ mPhysicalAddress = getPhysicalAddress();
+ if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ return false;
+ }
+ int targetPhysicalAddress = targetDevice.getPhysicalAddress();
+ if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ return false;
+ }
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ /**
* Listener used to get hotplug event from HDMI port.
*/
public interface HotplugEventListener {
diff --git a/core/java/android/hardware/hdmi/HdmiUtils.java b/core/java/android/hardware/hdmi/HdmiUtils.java
new file mode 100644
index 000000000000..308173816f13
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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.hardware.hdmi;
+
+/**
+ * Various utilities to handle HDMI CEC messages.
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+public class HdmiUtils {
+
+ /**
+ * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+ */
+ static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+ static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
+ private HdmiUtils() { /* cannot be instantiated */ }
+
+ /**
+ * Method to parse target physical address to the port number on the current device.
+ *
+ * <p>This check assumes target address is valid.
+ *
+ * @param targetPhysicalAddress is the physical address of the target device
+ * @param myPhysicalAddress is the physical address of the current device
+ * @return
+ * If the target device is under the current device, return the port number of current device
+ * that the target device is connected to. This also applies to the devices that are indirectly
+ * connected to the current device.
+ *
+ * <p>If the target device has the same physical address as the current device, return
+ * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+ *
+ * <p>If the target device is not under the current device, return
+ * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+ */
+ public static int getLocalPortFromPhysicalAddress(
+ int targetPhysicalAddress, int myPhysicalAddress) {
+ if (myPhysicalAddress == targetPhysicalAddress) {
+ return TARGET_SAME_PHYSICAL_ADDRESS;
+ }
+
+ int mask = 0xF000;
+ int finalMask = 0xF000;
+ int maskedAddress = myPhysicalAddress;
+
+ while (maskedAddress != 0) {
+ maskedAddress = myPhysicalAddress & mask;
+ finalMask |= mask;
+ mask >>= 4;
+ }
+
+ int portAddress = targetPhysicalAddress & finalMask;
+ if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+ return TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ mask <<= 4;
+ int port = portAddress & mask;
+ while ((port >> 4) != 0) {
+ port >>= 4;
+ }
+ return port;
+ }
+}
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 000000000000..93a8d41936cc
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable IpPrefixParcelable {
+ String address;
+ int prefixLength;
+} \ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 000000000000..af8e79b21f69
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable LinkAddressParcelable {
+ String address;
+ int prefixLength;
+ int flags;
+ int scope;
+} \ No newline at end of file
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 000000000000..b153dc70e1b8
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+ String ifaceName;
+ LinkAddressParcelable[] linkAddresses;
+ String[] dnses;
+ String[] pcscfs;
+ String[] validatedPrivateDnses;
+ boolean usePrivateDns;
+ String privateDnsServerName;
+ String domains;
+ RouteInfoParcelable[] routes;
+ ProxyInfoParcelable httpProxy;
+ int mtu;
+ String tcpBufferSizes;
+ IpPrefixParcelable nat64Prefix;
+ LinkPropertiesParcelable[] stackedLinks;
+} \ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 000000000000..59fd8467b820
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable ProxyInfoParcelable {
+ String host;
+ int port;
+ String[] exclusionList;
+ String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 000000000000..15bcdcfc2000
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+ IpPrefixParcelable destination;
+ String gatewayAddr;
+ String ifaceName;
+ int type;
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index e4622dbdc379..f51ba9a41a2b 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -306,9 +306,18 @@ public class GraphicsEnvironment {
String packageName,
String paths,
String devOptIn) {
- // Check for temporary rules if debuggable or root
- if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) {
- Log.v(TAG, "Skipping loading temporary rules file");
+ /**
+ * We only want to load a temp rules file for:
+ * - apps that are marked 'debuggable' in their manifest
+ * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
+ * debugging (PR_SET_DUMPABLE).
+ */
+ boolean appIsDebuggable = isDebuggable(context);
+ boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+ if (!(appIsDebuggable || deviceIsDebuggable)) {
+ Log.v(TAG, "Skipping loading temporary rules file: "
+ + "appIsDebuggable = " + appIsDebuggable + ", "
+ + "adbRootEnabled = " + deviceIsDebuggable);
return false;
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index c79589577366..44cb2212cd0c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -16,9 +16,13 @@
package android.provider;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.content.ContentResolver;
@@ -78,6 +82,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
public static String getProperty(String namespace, String name) {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
String compositeName = createCompositeName(namespace, name);
@@ -105,6 +110,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
public static boolean setProperty(
String namespace, String name, String value, boolean makeDefault) {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -125,6 +131,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
@@ -146,10 +153,12 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
public static void addOnPropertyChangedListener(
@NonNull String namespace,
@NonNull @CallbackExecutor Executor executor,
@NonNull OnPropertyChangedListener onPropertyChangedListener) {
+ // TODO enforce READ_DEVICE_CONFIG permission
synchronized (sLock) {
Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
if (oldNamespace == null) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 73e90d6ee628..b39d871c8637 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7732,6 +7732,23 @@ public final class Settings {
public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
/**
+ * Whether TV app uses non-system inputs.
+ *
+ * <p>
+ * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed,
+ * and 0 means non-system TV inputs are not allowed.
+ *
+ * <p>
+ * Devices such as sound bars may have changed the system property allow_third_party_inputs
+ * to false so the TV Application only uses HDMI and other built in inputs. This setting
+ * allows user to override the default and have the TV Application use third party TV inputs
+ * available on play store.
+ *
+ * @hide
+ */
+ public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs";
+
+ /**
* Whether automatic routing of system audio to USB audio peripheral is disabled.
* The value is boolean (1 or 0), where 1 means automatic routing is disabled,
* and 0 means automatic routing is enabled.
@@ -14109,7 +14126,7 @@ public final class Settings {
*
* @hide
*/
- // TODO(b/117663715): require a new read permission
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
static String getString(ContentResolver resolver, String name) {
return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
}
@@ -14132,8 +14149,7 @@ public final class Settings {
*
* @hide
*/
- // TODO(b/117663715): require a new write permission restricted to a single source
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
@Nullable String value, boolean makeDefault) {
return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault,
@@ -14155,7 +14171,7 @@ public final class Settings {
* @hide
*/
// TODO(b/117663715): require a new write permission restricted to a single source
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
@Nullable String prefix) {
try {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 163e3d5fab56..6f274477431f 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -121,6 +121,12 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
*/
public static final int SHOW_SOURCE_NOTIFICATION = 1 << 6;
+ /**
+ * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+ * from an Android automotive system Ui.
+ */
+ public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7;
+
final Context mContext;
final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bad2dbfebdc5..60393502bbe7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -69,6 +70,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* A View that displays web pages.
@@ -1688,6 +1690,84 @@ public class WebView extends AbsoluteLayout
return mProvider.getWebViewClient();
}
+
+ /**
+ * Gets the WebView renderer associated with this WebView.
+ *
+ * <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
+ * run in "multiprocess" mode. In multiprocess mode, rendering of web
+ * content is performed by a sandboxed renderer process separate to the
+ * application process. This renderer process may be shared with other
+ * WebViews in the application, but is not shared with other application
+ * processes.
+ *
+ * <p>If WebView is running in multiprocess mode, this method returns a
+ * handle to the renderer process associated with the WebView, which can
+ * be used to control the renderer process.
+ *
+ * @return the {@link WebViewRenderer} renderer handle associated
+ * with this {@link WebView}, or {@code null} if
+ * WebView is not runing in multiprocess mode.
+ */
+ @Nullable
+ public WebViewRenderer getWebViewRenderer() {
+ checkThread();
+ return mProvider.getWebViewRenderer();
+ }
+
+ /**
+ * Sets the renderer client object associated with this WebView.
+ *
+ * <p>The renderer client encapsulates callbacks relevant to WebView renderer
+ * state. See {@link WebViewRendererClient} for details.
+ *
+ * <p>Although many WebView instances may share a single underlying
+ * renderer, and renderers may live either in the application
+ * process, or in a sandboxed process that is isolated from the
+ * application process, instances of {@link WebViewRendererClient}
+ * are set per-WebView. Callbacks represent renderer events from
+ * the perspective of this WebView, and may or may not be correlated
+ * with renderer events affecting other WebViews.
+ *
+ * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
+ * @param webViewRendererClient the {@link WebViewRendererClient} object.
+ */
+ public void setWebViewRendererClient(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull WebViewRendererClient webViewRendererClient) {
+ checkThread();
+ mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+ }
+
+ /**
+ * Sets the renderer client object associated with this WebView.
+ *
+ * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+ *
+ * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+ * initialized on.
+ *
+ * @param webViewRendererClient the {@link WebViewRendererClient} object.
+ */
+ public void setWebViewRendererClient(
+ @Nullable WebViewRendererClient webViewRendererClient) {
+ checkThread();
+ mProvider.setWebViewRendererClient(null, webViewRendererClient);
+ }
+
+ /**
+ * Gets the renderer client object associated with this WebView.
+ *
+ * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
+ * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
+ * otherwise.
+ */
+ @Nullable
+ public WebViewRendererClient getWebViewRendererClient() {
+ checkThread();
+ return mProvider.getWebViewRendererClient();
+ }
+
/**
* Registers the interface to be used when content can not be handled by
* the rendering engine, and should be downloaded instead. This will replace
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95e7a986efd2..baf582693bd8 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -54,6 +54,7 @@ import android.webkit.WebView.VisualStateCallback;
import java.io.BufferedWriter;
import java.io.File;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* WebView backend provider interface: this interface is the abstract backend to a WebView
@@ -237,6 +238,14 @@ public interface WebViewProvider {
public WebViewClient getWebViewClient();
+ public WebViewRenderer getWebViewRenderer();
+
+ public void setWebViewRendererClient(
+ @Nullable Executor executor,
+ @Nullable WebViewRendererClient client);
+
+ public WebViewRendererClient getWebViewRendererClient();
+
public void setDownloadListener(DownloadListener listener);
public void setWebChromeClient(WebChromeClient client);
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderer.java
new file mode 100644
index 000000000000..532825485ed3
--- /dev/null
+++ b/core/java/android/webkit/WebViewRenderer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ */
+public abstract class WebViewRenderer {
+ /**
+ * Cause this renderer to terminate.
+ *
+ * <p>Calling this on a not yet started, or an already terminated renderer will have no effect.
+ *
+ * <p>Terminating a renderer process may have an effect on multiple {@link WebView} instances.
+ *
+ * <p>Renderer termination must be handled by properly overriding
+ * {@link WebViewClient#onRenderProcessGone} for every WebView that shares this
+ * renderer. If termination is not handled by all associated WebViews, then the application
+ * process will also be terminated.
+ *
+ * @return {@code true} if it was possible to terminate this renderer, {@code false} otherwise.
+ */
+ public abstract boolean terminate();
+
+ /**
+ * This class cannot be created by applications.
+ * @hide
+ */
+ public WebViewRenderer() {
+ }
+}
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRendererClient.java
new file mode 100644
index 000000000000..2fadf54fd434
--- /dev/null
+++ b/core/java/android/webkit/WebViewRendererClient.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Used to receive callbacks on {@link WebView} renderer events.
+ *
+ * WebViewRendererClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
+ * WebView#getWebViewRendererClient()}.
+ *
+ * Instances may be attached to multiple WebViews, and thus a single renderer event may cause
+ * a callback to be called multiple times with different WebView parameters.
+ */
+public abstract class WebViewRendererClient {
+ /**
+ * Called when the renderer currently associated with {@code view} becomes unresponsive as a
+ * result of a long running blocking task such as the execution of JavaScript.
+ *
+ * <p>If a WebView fails to process an input event, or successfully navigate to a new URL within
+ * a reasonable time frame, the renderer is considered to be unresponsive, and this callback
+ * will be called.
+ *
+ * <p>This callback will continue to be called at regular intervals as long as the renderer
+ * remains unresponsive. If the renderer becomes responsive again, {@link
+ * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
+ * subsequently be called unless another period of unresponsiveness is detected.
+ *
+ * <p>No action is taken by WebView as a result of this method call. Applications may
+ * choose to terminate the associated renderer via the object that is passed to this callback,
+ * if in multiprocess mode, however this must be accompanied by correctly handling
+ * {@link WebViewClient#onRenderProcessGone} for this WebView, and all other WebViews associated
+ * with the same renderer. Failure to do so will result in application termination.
+ *
+ * @param view The {@link WebView} for which unresponsiveness was detected.
+ * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+ * or {@code null} if WebView is running in single process mode.
+ */
+ public abstract void onRendererUnresponsive(
+ @NonNull WebView view, @Nullable WebViewRenderer renderer);
+
+ /**
+ * Called once when an unresponsive renderer currently associated with {@code view} becomes
+ * responsive.
+ *
+ * <p>After a WebView renderer becomes unresponsive, which is notified to the application by
+ * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
+ * renderer task to complete, returning the renderer to a responsive state. In that case,
+ * this method is called once to indicate responsiveness.
+ *
+ * <p>No action is taken by WebView as a result of this method call.
+ *
+ * @param view The {@link WebView} for which responsiveness was detected.
+ *
+ * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
+ * WebView is running in single process mode.
+ */
+ public abstract void onRendererResponsive(
+ @NonNull WebView view, @Nullable WebViewRenderer renderer);
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7813128d46c7..cf1f7bb2aac1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2532,6 +2532,16 @@
<permission android:name="android.permission.WRITE_GSERVICES"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to modify config settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+ android:protectionLevel="signature|configurator"/>
+
+ <!-- @SystemApi @hide Allows an application to read config settings.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_DEVICE_CONFIG"
+ android:protectionLevel="signature|preinstalled" />
+
<!-- @SystemApi @TestApi Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 18a42bc5ed0b..b15f72efd717 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -274,6 +274,9 @@
<!-- Additional flag from base permission type: this permission can be automatically
granted to the document manager -->
<flag name="documenter" value="0x40000" />
+ <!-- Additional flag from base permission type: this permission automatically
+ granted to device configurator -->
+ <flag name="configurator" value="0x80000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9a1360b18be8..aa1364f4a24e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2805,6 +2805,9 @@
<!-- Flag indicating which package name can access the persistent data partition -->
<string name="config_persistentDataPackageName" translatable="false"></string>
+ <!-- Flag indicating which package name can access DeviceConfig table -->
+ <string name="config_deviceConfiguratorPackageName" translatable="false"></string>
+
<!-- Flag indicating apps will skip sending hold request before merge. In this case
IMS service implementation will do both.i.e.hold followed by merge. -->
<bool name="skipHoldBeforeMerge">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd1ee2b0166d..eb0a7a1d8b10 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2140,6 +2140,7 @@
<java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
+ <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index e80cb6d0295b..86818c611c1f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -56,6 +56,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
<uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
<uses-permission android:name="android.permission.READ_LOGS"/>
@@ -65,6 +66,7 @@
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
new file mode 100644
index 000000000000..16be0b0a27c1
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hardware.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+ @Test
+ public void pathToPort_isMe() {
+ int targetPhysicalAddress = 0x1000;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+ }
+
+ @Test
+ public void pathToPort_isDirectlyBelow() {
+ int targetPhysicalAddress = 0x1100;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_isBelow() {
+ int targetPhysicalAddress = 0x1110;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_neitherMeNorBelow() {
+ int targetPhysicalAddress = 0x3000;
+ int myPhysicalAddress = 0x2000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2200;
+ myPhysicalAddress = 0x3300;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2213;
+ myPhysicalAddress = 0x2212;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2340;
+ myPhysicalAddress = 0x2310;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 13e548b2e688..93af0130d74c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -668,6 +668,7 @@ public class SettingsBackupTest {
Settings.Secure.SMS_DEFAULT_APPLICATION,
Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q
Settings.Secure.TRUST_AGENTS_INITIALIZED,
+ Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
Settings.Secure.TV_INPUT_CUSTOM_LABELS,
Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
Settings.Secure.TV_USER_SETUP_COMPLETE,
diff --git a/media/Android.bp b/media/Android.bp
index d5da6f266952..8ebc91a06f7a 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,4 +1,21 @@
java_library {
+ name: "media1",
+
+ srcs: [
+ ":media1-srcs",
+ ],
+
+ sdk_version: "system_current",
+}
+
+filegroup {
+ name: "media1-srcs",
+ srcs: [
+ "java/android/media/session/MediaSessionProviderService.java",
+ ],
+}
+
+java_library {
// TODO: include media2.jar in the media apex and add it to the bootclasspath.
name: "media2",
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 10a1e3a72225..01def960189a 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -163,7 +163,7 @@ public final class MediaCodecInfo {
// such as B-frame support, arithmetic coding...
public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user
- // from OMX_COLOR_FORMATTYPE
+ // from MediaCodecConstants
/** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
public static final int COLOR_FormatMonochrome = 1;
/** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
@@ -344,7 +344,7 @@ public final class MediaCodecInfo {
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
// COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
- // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
+ // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque.
public static final int COLOR_FormatSurface = 0x7F000789;
/**
@@ -435,8 +435,7 @@ public final class MediaCodecInfo {
public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00;
/**
- * Defined in the OpenMAX IL specs, color format values are drawn from
- * OMX_COLOR_FORMATTYPE.
+ * The color format for the media. This is one of the color constants defined in this class.
*/
public int[] colorFormats; // NOTE this array is modifiable by user
@@ -2879,7 +2878,9 @@ public final class MediaCodecInfo {
* {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
*/
public static final class CodecProfileLevel {
- // from OMX_VIDEO_AVCPROFILETYPE
+ // These constants were originally in-line with OMX values, but this
+ // correspondence is no longer maintained.
+
public static final int AVCProfileBaseline = 0x01;
public static final int AVCProfileMain = 0x02;
public static final int AVCProfileExtended = 0x04;
@@ -2890,7 +2891,6 @@ public final class MediaCodecInfo {
public static final int AVCProfileConstrainedBaseline = 0x10000;
public static final int AVCProfileConstrainedHigh = 0x80000;
- // from OMX_VIDEO_AVCLEVELTYPE
public static final int AVCLevel1 = 0x01;
public static final int AVCLevel1b = 0x02;
public static final int AVCLevel11 = 0x04;
@@ -2908,8 +2908,10 @@ public final class MediaCodecInfo {
public static final int AVCLevel5 = 0x4000;
public static final int AVCLevel51 = 0x8000;
public static final int AVCLevel52 = 0x10000;
+ public static final int AVCLevel6 = 0x20000;
+ public static final int AVCLevel61 = 0x40000;
+ public static final int AVCLevel62 = 0x80000;
- // from OMX_VIDEO_H263PROFILETYPE
public static final int H263ProfileBaseline = 0x01;
public static final int H263ProfileH320Coding = 0x02;
public static final int H263ProfileBackwardCompatible = 0x04;
@@ -2920,7 +2922,6 @@ public final class MediaCodecInfo {
public static final int H263ProfileInterlace = 0x80;
public static final int H263ProfileHighLatency = 0x100;
- // from OMX_VIDEO_H263LEVELTYPE
public static final int H263Level10 = 0x01;
public static final int H263Level20 = 0x02;
public static final int H263Level30 = 0x04;
@@ -2930,7 +2931,6 @@ public final class MediaCodecInfo {
public static final int H263Level60 = 0x40;
public static final int H263Level70 = 0x80;
- // from OMX_VIDEO_MPEG4PROFILETYPE
public static final int MPEG4ProfileSimple = 0x01;
public static final int MPEG4ProfileSimpleScalable = 0x02;
public static final int MPEG4ProfileCore = 0x04;
@@ -2948,7 +2948,6 @@ public final class MediaCodecInfo {
public static final int MPEG4ProfileAdvancedScalable = 0x4000;
public static final int MPEG4ProfileAdvancedSimple = 0x8000;
- // from OMX_VIDEO_MPEG4LEVELTYPE
public static final int MPEG4Level0 = 0x01;
public static final int MPEG4Level0b = 0x02;
public static final int MPEG4Level1 = 0x04;
@@ -2960,7 +2959,6 @@ public final class MediaCodecInfo {
public static final int MPEG4Level5 = 0x80;
public static final int MPEG4Level6 = 0x100;
- // from OMX_VIDEO_MPEG2PROFILETYPE
public static final int MPEG2ProfileSimple = 0x00;
public static final int MPEG2ProfileMain = 0x01;
public static final int MPEG2Profile422 = 0x02;
@@ -2968,14 +2966,12 @@ public final class MediaCodecInfo {
public static final int MPEG2ProfileSpatial = 0x04;
public static final int MPEG2ProfileHigh = 0x05;
- // from OMX_VIDEO_MPEG2LEVELTYPE
public static final int MPEG2LevelLL = 0x00;
public static final int MPEG2LevelML = 0x01;
public static final int MPEG2LevelH14 = 0x02;
public static final int MPEG2LevelHL = 0x03;
public static final int MPEG2LevelHP = 0x04;
- // from OMX_AUDIO_AACPROFILETYPE
public static final int AACObjectMain = 1;
public static final int AACObjectLC = 2;
public static final int AACObjectSSR = 3;
@@ -2990,16 +2986,13 @@ public final class MediaCodecInfo {
/** xHE-AAC (includes USAC) */
public static final int AACObjectXHE = 42;
- // from OMX_VIDEO_VP8LEVELTYPE
public static final int VP8Level_Version0 = 0x01;
public static final int VP8Level_Version1 = 0x02;
public static final int VP8Level_Version2 = 0x04;
public static final int VP8Level_Version3 = 0x08;
- // from OMX_VIDEO_VP8PROFILETYPE
public static final int VP8ProfileMain = 0x01;
- // from OMX_VIDEO_VP9PROFILETYPE
public static final int VP9Profile0 = 0x01;
public static final int VP9Profile1 = 0x02;
public static final int VP9Profile2 = 0x04;
@@ -3010,7 +3003,6 @@ public final class MediaCodecInfo {
public static final int VP9Profile2HDR10Plus = 0x4000;
public static final int VP9Profile3HDR10Plus = 0x8000;
- // from OMX_VIDEO_VP9LEVELTYPE
public static final int VP9Level1 = 0x1;
public static final int VP9Level11 = 0x2;
public static final int VP9Level2 = 0x4;
@@ -3026,14 +3018,12 @@ public final class MediaCodecInfo {
public static final int VP9Level61 = 0x1000;
public static final int VP9Level62 = 0x2000;
- // from OMX_VIDEO_HEVCPROFILETYPE
public static final int HEVCProfileMain = 0x01;
public static final int HEVCProfileMain10 = 0x02;
public static final int HEVCProfileMainStill = 0x04;
public static final int HEVCProfileMain10HDR10 = 0x1000;
public static final int HEVCProfileMain10HDR10Plus = 0x2000;
- // from OMX_VIDEO_HEVCLEVELTYPE
public static final int HEVCMainTierLevel1 = 0x1;
public static final int HEVCHighTierLevel1 = 0x2;
public static final int HEVCMainTierLevel2 = 0x4;
@@ -3067,7 +3057,6 @@ public final class MediaCodecInfo {
HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
HEVCHighTierLevel62;
- // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
public static final int DolbyVisionProfileDvavPer = 0x1;
public static final int DolbyVisionProfileDvavPen = 0x2;
public static final int DolbyVisionProfileDvheDer = 0x4;
@@ -3079,7 +3068,6 @@ public final class MediaCodecInfo {
public static final int DolbyVisionProfileDvheSt = 0x100;
public static final int DolbyVisionProfileDvavSe = 0x200;
- // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
public static final int DolbyVisionLevelHd24 = 0x1;
public static final int DolbyVisionLevelHd30 = 0x2;
public static final int DolbyVisionLevelFhd24 = 0x4;
@@ -3090,17 +3078,44 @@ public final class MediaCodecInfo {
public static final int DolbyVisionLevelUhd48 = 0x80;
public static final int DolbyVisionLevelUhd60 = 0x100;
+ public static final int AV1Profile0 = 0x1;
+ public static final int AV1Profile1 = 0x2;
+ public static final int AV1Profile2 = 0x4;
+
+ public static final int AV1Level2 = 0x1;
+ public static final int AV1Level21 = 0x2;
+ public static final int AV1Level22 = 0x4;
+ public static final int AV1Level23 = 0x8;
+ public static final int AV1Level3 = 0x10;
+ public static final int AV1Level31 = 0x20;
+ public static final int AV1Level32 = 0x40;
+ public static final int AV1Level33 = 0x80;
+ public static final int AV1Level4 = 0x100;
+ public static final int AV1Level41 = 0x200;
+ public static final int AV1Level42 = 0x400;
+ public static final int AV1Level43 = 0x800;
+ public static final int AV1Level5 = 0x1000;
+ public static final int AV1Level51 = 0x2000;
+ public static final int AV1Level52 = 0x4000;
+ public static final int AV1Level53 = 0x8000;
+ public static final int AV1Level6 = 0x10000;
+ public static final int AV1Level61 = 0x20000;
+ public static final int AV1Level62 = 0x40000;
+ public static final int AV1Level63 = 0x80000;
+ public static final int AV1Level7 = 0x100000;
+ public static final int AV1Level71 = 0x200000;
+ public static final int AV1Level72 = 0x400000;
+ public static final int AV1Level73 = 0x800000;
+
/**
- * Defined in the OpenMAX IL specs, depending on the type of media
- * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
- * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
+ * The profile of the media content. Depending on the type of media this can be
+ * one of the profile values defined in this class.
*/
public int profile;
/**
- * Defined in the OpenMAX IL specs, depending on the type of media
- * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
- * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+ * The level of the media content. Depending on the type of media this can be
+ * one of the level values defined in this class.
*
* Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
* not advertise a profile level support. For those VP9 decoders, please use
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 594a22457cc3..c82b5f6f12a1 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -124,6 +124,7 @@ import java.util.stream.Collectors;
public final class MediaFormat {
public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+ public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
public static final String MIMETYPE_VIDEO_AVC = "video/avc";
public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index 95ee4c039f4b..c7b891151201 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -152,9 +152,7 @@ public final class Session2Token implements Parcelable {
mType = in.readInt();
mPackageName = in.readString();
mServiceName = in.readString();
- // TODO: Uncomment below and stop hardcode mSessionLink
- mSessionLink = null;
- //mSessionLink = ISession.Stub.asInterface(in.readStrongBinder());
+ mSessionLink = Session2Link.CREATOR.createFromParcel(in);
mComponentName = ComponentName.unflattenFromString(in.readString());
}
@@ -164,8 +162,7 @@ public final class Session2Token implements Parcelable {
dest.writeInt(mType);
dest.writeString(mPackageName);
dest.writeString(mServiceName);
- // TODO: Uncomment below
- //dest.writeStrongBinder(mSessionLink.getBinder());
+ mSessionLink.writeToParcel(dest, flags);
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
}
diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java
new file mode 100644
index 000000000000..9a346ff4a12e
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Abstract class for mainline module services.
+ *
+ * @hide // TODO: Make it as a @SystemApi
+ */
+public abstract class MediaSessionProviderService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // TODO: Return IMediaSessionProviderService.Stub()
+ return null;
+ }
+}
diff --git a/media/packages/MediaCore/Android.bp b/media/packages/MediaCore/Android.bp
new file mode 100644
index 000000000000..c7fd58bf933a
--- /dev/null
+++ b/media/packages/MediaCore/Android.bp
@@ -0,0 +1,21 @@
+android_app {
+ name: "MediaCore",
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ // TODO: Temporarily statically linked. Should go into "libs"
+ "media1",
+ ],
+
+ // System app
+ platform_apis: true,
+
+ // Privileged app
+ privileged: true,
+
+ // Make sure that the implementation only relies on SDK or system APIs.
+ sdk_version: "system_current",
+}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
new file mode 100644
index 000000000000..4e2b274511e8
--- /dev/null
+++ b/media/packages/MediaCore/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/AndroidManifest.xml
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
+ android:sharedUserLabel="@string/android_system_label">
+ <application android:process="system"
+ android:persistent="true"
+ android:directBootAware="true">
+ <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
+ <intent-filter>
+ <action android:name="android.media.session.MediaSessionProviderService"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml
new file mode 100644
index 000000000000..59fd635b905f
--- /dev/null
+++ b/media/packages/MediaCore/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Label for the Android system components when they are shown to the user. -->
+ <string name="android_system_label" translatable="false">Android System</string>
+</resources>
+
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
new file mode 100644
index 000000000000..43b95ab7ebdb
--- /dev/null
+++ b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media;
+
+import android.content.Context;
+import android.media.session.MediaSessionProviderService;
+import android.os.PowerManager;
+import android.util.Log;
+
+/**
+ * System implementation of MediaSessionProviderService
+ */
+public class AmlMediaSessionProviderService extends MediaSessionProviderService {
+ private static final String TAG = "AmlMediaSessionProviderS";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private Context mContext;
+
+ public AmlMediaSessionProviderService(Context context) {
+ mContext = context;
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bce559396ddd..5153f9ea86d1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1052,7 +1052,7 @@ public class SettingsProvider extends ContentProvider {
}
// TODO(b/117663715): Ensure the caller can access the setting.
- // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());
+ // enforceReadPermission(READ_DEVICE_CONFIG);
// Get the value.
synchronized (mLock) {
@@ -1088,8 +1088,9 @@ public class SettingsProvider extends ContentProvider {
private boolean mutateConfigSetting(String name, String value, String prefix,
boolean makeDefault, int operation, int mode) {
- // TODO(b/117663715): check the new permission when it's added.
- // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+ // TODO(b/117663715): Ensure the caller can access the setting.
+ // enforceReadPermission(WRITE_DEVICE_CONFIG);
// Perform the mutation.
synchronized (mLock) {
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 87a4f603f70b..ebdf9b1a2791 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<uses-permission android:name="android.permission.MANAGE_USERS"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9b775e058ea8..b903142c44c6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -57,6 +57,8 @@
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
<!-- Development tool permissions granted to the shell. -->
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
index 0d72657bb2df..6f7f39810608 100644
--- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -19,15 +19,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <TextClock
+ <include
android:id="@+id/digital_clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:letterSpacing="0.03"
- android:singleLine="true"
- style="@style/widget_big"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format"
+ layout="@layout/text_clock"
/>
<com.android.keyguard.clock.ImageClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
index cf4a573834dd..e88e2c94e74f 100644
--- a/packages/SystemUI/res-keyguard/layout/digital_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
@@ -20,16 +20,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true">
- <TextClock
+ <include
android:id="@+id/lock_screen_clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:letterSpacing="0.03"
- android:singleLine="true"
- style="@style/widget_big"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format" />
+ layout="@layout/text_clock"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index d52866fbd444..463367b2c600 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -30,17 +30,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true">
- <TextClock
+ <include
android:id="@+id/default_clock_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:letterSpacing="0.03"
- android:textColor="?attr/wallpaperTextColor"
- android:singleLine="true"
- style="@style/widget_big"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format" />
+ layout="@layout/text_clock" />
</FrameLayout>
<include layout="@layout/keyguard_status_area"
android:id="@+id/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
index 9033fce881c4..64b676f55fd6 100644
--- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -19,15 +19,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <TextClock
+ <include
android:id="@+id/digital_clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:letterSpacing="0.03"
- android:singleLine="true"
- style="@style/widget_big"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format"
+ layout="@layout/text_clock"
/>
<com.android.keyguard.clock.StretchAnalogClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml
new file mode 100644
index 000000000000..b61ad9c4fc11
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<TextClock
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:letterSpacing="0.03"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:elegantTextHeight="false"
+/>
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index 7f4e0d21078f..f932303473bd 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.android.systemui.HardwareUiLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|right"
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 633f8686b804..bd34beac7fd6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -114,5 +114,8 @@
<item type="id" name="aod_mask_transition_progress_tag" />
<item type="id" name="aod_mask_transition_progress_end_tag" />
<item type="id" name="aod_mask_transition_progress_start_tag" />
+
+ <!-- Global Actions Menu -->
+ <item type="id" name="global_actions_view" />
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a8094d20d5a2..e9ce1a670fe1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -248,10 +248,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
mClockView.setShowCurrentUserTime(showCurrentUserTime);
}
- public void setElegantTextHeight(boolean elegant) {
- mClockView.setElegantTextHeight(elegant);
- }
-
public void setTextSize(int unit, float size) {
mClockView.setTextSize(unit, size);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index f0cdc890306f..7ae4c41d318f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -202,10 +202,6 @@ public class KeyguardStatusView extends GridLayout implements
updateOwnerInfo();
updateLogoutView();
updateDark();
-
- // Disable elegant text height because our fancy colon makes the ymin value huge for no
- // reason.
- mClockView.setElegantTextHeight(false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 16e869e9d317..e28aa9d369cb 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -37,23 +37,25 @@ import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;
-public class HardwareUiLayout extends LinearLayout implements Tunable {
+/**
+ * Layout for placing two containers at a specific physical position on the device, relative to the
+ * device's hardware, regardless of screen rotation.
+ */
+public class HardwareUiLayout extends MultiListLayout implements Tunable {
private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
private final int[] mTmp2 = new int[2];
- private View mList;
- private View mSeparatedView;
+ private ViewGroup mList;
+ private ViewGroup mSeparatedView;
private int mOldHeight;
private boolean mAnimating;
private AnimatorSet mAnimation;
private View mDivision;
- private boolean mHasOutsideTouch;
private HardwareBgDrawable mListBackground;
private HardwareBgDrawable mSeparatedViewBackground;
private Animator mAnimator;
private boolean mCollapse;
- private boolean mHasSeparatedButton;
private int mEndPoint;
private boolean mEdgeBleed;
private boolean mRoundedDivider;
@@ -67,6 +69,35 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
}
@Override
+ protected ViewGroup getSeparatedView() {
+ return findViewById(com.android.systemui.R.id.separated_button);
+ }
+
+ @Override
+ protected ViewGroup getListView() {
+ return findViewById(android.R.id.list);
+ }
+
+ @Override
+ public void removeAllItems() {
+ if (mList != null) {
+ mList.removeAllViews();
+ }
+ if (mSeparatedView != null) {
+ mSeparatedView.removeAllViews();
+ }
+ }
+
+ @Override
+ public ViewGroup getParentView(boolean separated, int index) {
+ if (separated) {
+ return getSeparatedView();
+ } else {
+ return getListView();
+ }
+ }
+
+ @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
updateSettings();
@@ -137,9 +168,9 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mList == null) {
if (getChildCount() != 0) {
- mList = getChildAt(0);
+ mList = getListView();
mList.setBackground(mListBackground);
- mSeparatedView = getChildAt(1);
+ mSeparatedView = getSeparatedView();
mSeparatedView.setBackground(mSeparatedViewBackground);
updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
mOldHeight = mList.getMeasuredHeight();
@@ -187,7 +218,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
} else {
rotateLeft();
}
- if (mHasSeparatedButton) {
+ if (mHasSeparatedView) {
if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
// Separated view has top margin, so seascape separated view need special rotation,
// not a full left or right rotation.
@@ -408,8 +439,8 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
if (mList == null) return;
// If got separated button, setRotatedBackground to false,
// all items won't get white background.
- mListBackground.setRotatedBackground(mHasSeparatedButton);
- mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
+ mListBackground.setRotatedBackground(mHasSeparatedView);
+ mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView);
if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
int index = mRotatedBackground ? 0 : 1;
mDivision.getLocationOnScreen(mTmp2);
@@ -460,21 +491,21 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
case RotationUtils.ROTATION_LANDSCAPE:
defaultTopPadding = getPaddingLeft();
viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+ separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
screenHeight = getMeasuredWidth();
targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
break;
case RotationUtils.ROTATION_SEASCAPE:
defaultTopPadding = getPaddingRight();
viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+ separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
screenHeight = getMeasuredWidth();
targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
break;
default: // Portrait
defaultTopPadding = getPaddingTop();
viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
- separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
+ separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0;
screenHeight = getMeasuredHeight();
targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
break;
@@ -491,30 +522,10 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
return super.getOutlineProvider();
}
- public void setOutsideTouchListener(OnClickListener onClickListener) {
- mHasOutsideTouch = true;
- requestLayout();
- setOnClickListener(onClickListener);
- setClickable(true);
- setFocusable(true);
- }
-
public void setCollapse() {
mCollapse = true;
}
- public void setHasSeparatedButton(boolean hasSeparatedButton) {
- mHasSeparatedButton = hasSeparatedButton;
- }
-
- public static HardwareUiLayout get(View v) {
- if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
- if (v.getParent() instanceof View) {
- return get((View) v.getParent());
- }
- return null;
- }
-
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
if (mHasOutsideTouch || (mList == null)) {
inoutInfo.setTouchableInsets(
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
new file mode 100644
index 000000000000..0c7a9a9fffd2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Layout class representing the Global Actions menu which appears when the power button is held.
+ */
+public abstract class MultiListLayout extends LinearLayout {
+ boolean mHasOutsideTouch;
+ boolean mHasSeparatedView;
+
+ int mExpectedSeparatedItemCount;
+ int mExpectedListItemCount;
+
+ public MultiListLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ protected abstract ViewGroup getSeparatedView();
+
+ protected abstract ViewGroup getListView();
+
+ /**
+ * Removes all child items from the separated and list views, if they exist.
+ */
+ public abstract void removeAllItems();
+
+ /**
+ * Get the parent view which will be used to contain the item at the specified index.
+ * @param separated Whether or not this index refers to a position in the separated or list
+ * container.
+ * @param index The index of the item within the container.
+ * @return The parent ViewGroup which will be used to contain the specified item
+ * after it has been added to the layout.
+ */
+ public abstract ViewGroup getParentView(boolean separated, int index);
+
+ /**
+ * Sets the divided view, which may have a differently-colored background.
+ */
+ public abstract void setDivisionView(View v);
+
+ /**
+ * Set the view accessibility delegate for the list view container.
+ */
+ public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) {
+ getListView().setAccessibilityDelegate(delegate);
+ }
+
+ protected void setSeparatedViewVisibility(boolean visible) {
+ getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Sets the number of items expected to be rendered in the separated container. This allows the
+ * layout to correctly determine which parent containers will be used for items before they have
+ * beenadded to the layout.
+ * @param count The number of items expected.
+ */
+ public void setExpectedSeparatedItemCount(int count) {
+ mExpectedSeparatedItemCount = count;
+ }
+
+ /**
+ * Sets the number of items expected to be rendered in the list container. This allows the
+ * layout to correctly determine which parent containers will be used for items before they have
+ * beenadded to the layout.
+ * @param count The number of items expected.
+ */
+ public void setExpectedListItemCount(int count) {
+ mExpectedListItemCount = count;
+ }
+
+ /**
+ * Sets whether the separated view should be shown, and handles updating visibility on
+ * that view.
+ */
+ public void setHasSeparatedView(boolean hasSeparatedView) {
+ mHasSeparatedView = hasSeparatedView;
+ setSeparatedViewVisibility(hasSeparatedView);
+ }
+
+ /**
+ * Sets this layout to respond to an outside touch listener.
+ */
+ public void setOutsideTouchListener(OnClickListener onClickListener) {
+ mHasOutsideTouch = true;
+ requestLayout();
+ setOnClickListener(onClickListener);
+ setClickable(true);
+ setFocusable(true);
+ }
+
+ /**
+ * Retrieve the MultiListLayout associated with the given view.
+ */
+ public static MultiListLayout get(View v) {
+ if (v instanceof MultiListLayout) return (MultiListLayout) v;
+ if (v.getParent() instanceof View) {
+ return get((View) v.getParent());
+ }
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 268245bd4acd..7b18fad0e105 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -67,10 +67,8 @@ import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.R;
@@ -86,8 +84,8 @@ import com.android.internal.util.ScreenRecordHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
import com.android.systemui.Interpolators;
+import com.android.systemui.MultiListLayout;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -490,6 +488,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
public boolean showBeforeProvisioning() {
return true;
}
+
+ @Override
+ public boolean shouldBeSeparated() {
+ return true;
+ }
}
private final class RestartAction extends SinglePressAction implements LongPressAction {
@@ -926,6 +929,34 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return getItem(position).isEnabled();
}
+ public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) {
+ ArrayList<Action> separatedActions = new ArrayList<Action>();
+ if (!shouldUseSeparatedView) {
+ return separatedActions;
+ }
+ for (int i = 0; i < mItems.size(); i++) {
+ final Action action = mItems.get(i);
+ if (action.shouldBeSeparated()) {
+ separatedActions.add(action);
+ }
+ }
+ return separatedActions;
+ }
+
+ public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) {
+ if (!shouldUseSeparatedView) {
+ return new ArrayList<Action>(mItems);
+ }
+ ArrayList<Action> listActions = new ArrayList<Action>();
+ for (int i = 0; i < mItems.size(); i++) {
+ final Action action = mItems.get(i);
+ if (!action.shouldBeSeparated()) {
+ listActions.add(action);
+ }
+ }
+ return listActions;
+ }
+
@Override
public boolean areAllItemsEnabled() {
return false;
@@ -965,7 +996,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
// Everything but screenshot, the last item, gets white background.
if (position == getCount() - 1) {
- HardwareUiLayout.get(parent).setDivisionView(view);
+ MultiListLayout.get(parent).setDivisionView(view);
}
return view;
}
@@ -1004,6 +1035,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
boolean showBeforeProvisioning();
boolean isEnabled();
+
+ default boolean shouldBeSeparated() {
+ return false;
+ }
}
/**
@@ -1423,9 +1458,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final Context mContext;
private final MyAdapter mAdapter;
- private final LinearLayout mListView;
- private final FrameLayout mSeparatedView;
- private final HardwareUiLayout mHardwareLayout;
+ private final MultiListLayout mGlobalActionsLayout;
private final OnClickListener mClickListener;
private final OnItemLongClickListener mLongClickListener;
private final GradientDrawable mGradientDrawable;
@@ -1466,16 +1499,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
setContentView(com.android.systemui.R.layout.global_actions_wrapped);
- mListView = findViewById(android.R.id.list);
- mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
- if (!mShouldDisplaySeparatedButton) {
- mSeparatedView.setVisibility(View.GONE);
- }
- mHardwareLayout = HardwareUiLayout.get(mListView);
- mHardwareLayout.setOutsideTouchListener(view -> dismiss());
- mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
- setTitle(R.string.global_actions);
- mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ mGlobalActionsLayout = (MultiListLayout)
+ findViewById(com.android.systemui.R.id.global_actions_view);
+ mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
+ mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton);
+ mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public boolean dispatchPopulateAccessibilityEvent(
View host, AccessibilityEvent event) {
@@ -1484,20 +1512,33 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return true;
}
});
+ setTitle(R.string.global_actions);
}
private void updateList() {
- mListView.removeAllViews();
- mSeparatedView.removeAllViews();
+ mGlobalActionsLayout.removeAllItems();
+ ArrayList<Action> separatedActions =
+ mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton);
+ ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton);
+ mGlobalActionsLayout.setExpectedListItemCount(listActions.size());
+ mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size());
+
for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
- ? mSeparatedView : mListView;
- View v = mAdapter.getView(i, null, parentView);
+ Action action = mAdapter.getItem(i);
+ int separatedIndex = separatedActions.indexOf(action);
+ ViewGroup parent;
+ if (separatedIndex != -1) {
+ parent = mGlobalActionsLayout.getParentView(true, separatedIndex);
+ } else {
+ int listIndex = listActions.indexOf(action);
+ parent = mGlobalActionsLayout.getParentView(false, listIndex);
+ }
+ View v = mAdapter.getView(i, null, parent);
final int pos = i;
v.setOnClickListener(view -> mClickListener.onClick(this, pos));
v.setOnLongClickListener(view ->
mLongClickListener.onItemLongClick(null, v, pos, 0));
- parentView.addView(v);
+ parent.addView(v);
}
}
@@ -1543,9 +1584,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
super.show();
mShowing = true;
mGradientDrawable.setAlpha(0);
- mHardwareLayout.setTranslationX(getAnimTranslation());
- mHardwareLayout.setAlpha(0);
- mHardwareLayout.animate()
+ mGlobalActionsLayout.setTranslationX(getAnimTranslation());
+ mGlobalActionsLayout.setAlpha(0);
+ mGlobalActionsLayout.animate()
.alpha(1)
.translationX(0)
.setDuration(300)
@@ -1564,9 +1605,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return;
}
mShowing = false;
- mHardwareLayout.setTranslationX(0);
- mHardwareLayout.setAlpha(1);
- mHardwareLayout.animate()
+ mGlobalActionsLayout.setTranslationX(0);
+ mGlobalActionsLayout.setAlpha(1);
+ mGlobalActionsLayout.animate()
.alpha(0)
.translationX(getAnimTranslation())
.setDuration(300)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index eea44906029d..839b06cec496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -33,6 +33,13 @@ public interface NotificationEntryListener {
default void onPendingEntryAdded(NotificationEntry entry) {
}
+ // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar
+ /**
+ * Called when a new entry is created but before it has been filtered or displayed to the user.
+ */
+ default void onBeforeNotificationAdded(NotificationEntry entry) {
+ }
+
/**
* Called when a new entry is created.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 45db00210a2e..989e781ab5ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,11 +18,9 @@ package com.android.systemui.statusbar.notification;
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
-import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,7 +39,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
@@ -68,8 +65,6 @@ public class NotificationEntryManager implements
@VisibleForTesting
protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
- private final DeviceProvisionedController mDeviceProvisionedController =
- Dependency.get(DeviceProvisionedController.class);
private final ForegroundServiceController mForegroundServiceController =
Dependency.get(ForegroundServiceController.class);
@@ -81,25 +76,12 @@ public class NotificationEntryManager implements
private NotificationListenerService.RankingMap mLatestRankingMap;
@VisibleForTesting
protected NotificationData mNotificationData;
- private NotificationListContainer mListContainer;
+
@VisibleForTesting
final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
= new ArrayList<>();
private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
- private final DeviceProvisionedController.DeviceProvisionedListener
- mDeviceProvisionedListener =
- new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onDeviceProvisionedChanged() {
- updateNotifications();
- }
- };
-
- public void destroy() {
- mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NotificationEntryManager state:");
@@ -151,9 +133,6 @@ public class NotificationEntryManager implements
HeadsUpManager headsUpManager) {
mPresenter = presenter;
mNotificationData.setHeadsUpManager(headsUpManager);
- mListContainer = listContainer;
-
- mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
}
/** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -227,7 +206,9 @@ public class NotificationEntryManager implements
listener.onEntryInflated(entry, inflatedFlags);
}
mNotificationData.add(entry);
- tagForeground(entry.notification);
+ for (NotificationEntryListener listener : mNotificationEntryListeners) {
+ listener.onBeforeNotificationAdded(entry);
+ }
updateNotifications();
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationAdded(entry);
@@ -283,7 +264,6 @@ public class NotificationEntryManager implements
if (entry.rowExists()) {
entry.removeRow();
- mListContainer.cleanUpViewStateForEntry(entry);
}
// Let's remove the children if this was a summary
@@ -368,19 +348,6 @@ public class NotificationEntryManager implements
}
}
- @VisibleForTesting
- void tagForeground(StatusBarNotification notification) {
- ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
- notification.getUserId(), notification.getPackageName());
- if (activeOps != null) {
- int N = activeOps.size();
- for (int i = 0; i < N; i++) {
- updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
- notification.getPackageName(), true);
- }
- }
- }
-
@Override
public void addNotification(StatusBarNotification notification,
NotificationListenerService.RankingMap ranking) {
@@ -391,15 +358,6 @@ public class NotificationEntryManager implements
}
}
- public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
- String foregroundKey = mForegroundServiceController.getStandardLayoutKey(
- UserHandle.getUserId(uid), pkg);
- if (foregroundKey != null) {
- mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
- updateNotifications();
- }
- }
-
private void updateNotificationInternal(StatusBarNotification notification,
NotificationListenerService.RankingMap ranking) throws InflationException {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
@@ -452,8 +410,9 @@ public class NotificationEntryManager implements
public void updateNotifications() {
mNotificationData.filterAndSort();
-
- mPresenter.updateNotificationViews();
+ if (mPresenter != null) {
+ mPresenter.updateNotificationViews();
+ }
}
public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
new file mode 100644
index 000000000000..88f4ca239af4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * Root controller for the list of notifications in the shade.
+ *
+ * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
+ * domain-specific behavior (ARC, etc) to subcontrollers.
+ */
+public class NotificationListController {
+ private final NotificationEntryManager mEntryManager;
+ private final NotificationListContainer mListContainer;
+ private final ForegroundServiceController mForegroundServiceController;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+
+ public NotificationListController(
+ NotificationEntryManager entryManager,
+ NotificationListContainer listContainer,
+ ForegroundServiceController foregroundServiceController,
+ DeviceProvisionedController deviceProvisionedController) {
+ mEntryManager = checkNotNull(entryManager);
+ mListContainer = checkNotNull(listContainer);
+ mForegroundServiceController = checkNotNull(foregroundServiceController);
+ mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+ }
+
+ /**
+ * Causes the controller to register listeners on its dependencies. This method must be called
+ * before the controller is ready to perform its duties.
+ */
+ public void bind() {
+ mEntryManager.addNotificationEntryListener(mEntryListener);
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ }
+
+ /** Should be called when the list controller is being destroyed. */
+ public void destroy() {
+ mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
+ }
+
+ @SuppressWarnings("FieldCanBeLocal")
+ private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+ @Override
+ public void onEntryRemoved(
+ NotificationEntry entry,
+ NotificationVisibility visibility,
+ boolean removedByUser) {
+ mListContainer.cleanUpViewStateForEntry(entry);
+ }
+
+ @Override
+ public void onBeforeNotificationAdded(NotificationEntry entry) {
+ tagForeground(entry.notification);
+ }
+ };
+
+ private final DeviceProvisionedListener mDeviceProvisionedListener =
+ new DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ mEntryManager.updateNotifications();
+ }
+ };
+
+ // TODO: This method is horrifically inefficient
+ private void tagForeground(StatusBarNotification notification) {
+ ArraySet<Integer> activeOps =
+ mForegroundServiceController.getAppOps(
+ notification.getUserId(), notification.getPackageName());
+ if (activeOps != null) {
+ int len = activeOps.size();
+ for (int i = 0; i < len; i++) {
+ updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
+ notification.getPackageName(), true);
+ }
+ }
+ }
+
+ /** When an app op changes, propagate that change to notifications. */
+ public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+ String foregroundKey =
+ mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
+ if (foregroundKey != null) {
+ mEntryManager
+ .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
+ mEntryManager.updateNotifications();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 853d7ab9a76d..3568f2846a51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -612,9 +612,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
anim.setStartDelay(mAnimationDelay);
anim.setDuration(mAnimationDuration);
anim.addListener(new AnimatorListenerAdapter() {
+ private Callback lastCallback = mCallback;
+
@Override
public void onAnimationEnd(Animator animation) {
- onFinished();
+ onFinished(lastCallback);
scrim.setTag(TAG_KEY_ANIM, null);
dispatchScrimsVisible();
@@ -672,14 +674,23 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
}
private void onFinished() {
+ onFinished(mCallback);
+ }
+
+ private void onFinished(Callback callback) {
if (mWakeLockHeld) {
mWakeLock.release();
mWakeLockHeld = false;
}
- if (mCallback != null) {
- mCallback.onFinished();
- mCallback = null;
+
+ if (callback != null) {
+ callback.onFinished();
+
+ if (callback == mCallback) {
+ mCallback = null;
+ }
}
+
// When unlocking with fingerprint, we'll fade the scrims from black to transparent.
// At the end of the animation we need to remove the tint.
if (mState == ScrimState.UNLOCKED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7569a50a8c54..ed71598e22ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -196,6 +196,7 @@ import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationListController;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -387,6 +388,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private NotificationGutsManager mGutsManager;
protected NotificationLogger mNotificationLogger;
protected NotificationEntryManager mEntryManager;
+ private NotificationListController mNotificationListController;
private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private NotificationRowBinder mNotificationRowBinder;
protected NotificationViewHierarchyManager mViewHierarchyManager;
@@ -593,7 +595,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
mForegroundServiceController.onAppOpChanged(code, uid, packageName, active);
Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
- mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
+ mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active);
});
}
@@ -1044,6 +1046,13 @@ public class StatusBar extends SystemUI implements DemoMode,
mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
mNotificationAlertingManager);
+ mNotificationListController =
+ new NotificationListController(
+ mEntryManager,
+ (NotificationListContainer) mStackScroller,
+ mForegroundServiceController,
+ mDeviceProvisionedController);
+
mAppOpsController.addCallback(APP_OPS, this);
mNotificationListener.setUpWithPresenter(mPresenter);
mNotificationShelf.setOnActivatedListener(mPresenter);
@@ -1056,6 +1065,7 @@ public class StatusBar extends SystemUI implements DemoMode,
this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
+ mNotificationListController.bind();
}
/**
@@ -2831,7 +2841,7 @@ public class StatusBar extends SystemUI implements DemoMode,
} catch (RemoteException e) {
// Ignore.
}
- mEntryManager.destroy();
+ mNotificationListController.destroy();
// End old BaseStatusBar.destroy().
if (mStatusBarWindow != null) {
mWindowManager.removeViewImmediate(mStatusBarWindow);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d937f93482d5..9ce6ae139998 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -22,19 +22,15 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -49,7 +45,6 @@ import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.ArraySet;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
@@ -79,8 +74,6 @@ import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -346,7 +339,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(mEntryListener, never()).onInflationError(any(), any());
- verify(mListContainer).cleanUpViewStateForEntry(mEntry);
verify(mPresenter).updateNotificationViews();
verify(mEntryListener).onEntryRemoved(
mEntry, null, false /* removedByUser */);
@@ -401,90 +393,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
@Test
- public void testUpdateAppOps_foregroundNoti() {
- com.android.systemui.util.Assert.isNotMainThread();
-
- when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
- .thenReturn(mEntry.key);
- mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
-
- mEntryManager.updateNotificationsForAppOp(
- AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
- mEntry.notification.getPackageName(), true);
-
- verify(mPresenter, times(1)).updateNotificationViews();
- assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains(
- AppOpsManager.OP_CAMERA));
- }
-
- @Test
- public void testUpdateAppOps_otherNoti() {
- com.android.systemui.util.Assert.isNotMainThread();
-
- when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
- .thenReturn(null);
- mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
-
- verify(mPresenter, never()).updateNotificationViews();
- }
-
- @Test
- public void testAddNotificationExistingAppOps() {
- mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
- ArraySet<Integer> expected = new ArraySet<>();
- expected.add(3);
- expected.add(235);
- expected.add(1);
-
- when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn(expected);
- when(mForegroundServiceController.getStandardLayoutKey(
- mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-
- mEntryManager.tagForeground(mEntry.notification);
-
- Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size());
- for (int op : expected) {
- assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op));
- }
- }
-
- @Test
- public void testAdd_noExistingAppOps() {
- mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
- when(mForegroundServiceController.getStandardLayoutKey(
- mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn(mEntry.key);
- when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn(null);
-
- mEntryManager.tagForeground(mEntry.notification);
- Assert.assertEquals(0, mEntry.mActiveAppOps.size());
- }
-
- @Test
- public void testAdd_existingAppOpsNotForegroundNoti() {
- mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(3);
- ops.add(235);
- ops.add(1);
- when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn(ops);
- when(mForegroundServiceController.getStandardLayoutKey(
- mEntry.notification.getUserId(),
- mEntry.notification.getPackageName())).thenReturn("something else");
-
- mEntryManager.tagForeground(mEntry.notification);
- Assert.assertEquals(0, mEntry.mActiveAppOps.size());
- }
-
- @Test
public void testUpdateNotificationRanking() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
new file mode 100644
index 000000000000..4b5037bb3f64
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationListControllerTest extends SysuiTestCase {
+ private NotificationListController mController;
+
+ @Mock private NotificationEntryManager mEntryManager;
+ @Mock private NotificationListContainer mListContainer;
+ @Mock private ForegroundServiceController mForegroundServiceController;
+ @Mock private DeviceProvisionedController mDeviceProvisionedController;
+
+ @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
+ @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor;
+
+ private NotificationEntryListener mEntryListener;
+ private DeviceProvisionedListener mProvisionedListener;
+
+ // TODO: Remove this once EntryManager no longer needs to be mocked
+ private NotificationData mNotificationData = new NotificationData();
+
+ private int mNextNotifId = 0;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
+
+ mController = new NotificationListController(
+ mEntryManager,
+ mListContainer,
+ mForegroundServiceController,
+ mDeviceProvisionedController);
+ mController.bind();
+
+ // Capture callbacks passed to mocks
+ verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+ mEntryListener = mEntryListenerCaptor.getValue();
+ verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture());
+ mProvisionedListener = mProvisionedCaptor.getValue();
+ }
+
+ @Test
+ public void testCleanUpViewStateOnEntryRemoved() {
+ final NotificationEntry entry = buildEntry();
+ mEntryListener.onEntryRemoved(
+ entry,
+ NotificationVisibility.obtain(entry.key, 0, 0, true),
+ false);
+ verify(mListContainer).cleanUpViewStateForEntry(entry);
+ }
+
+ @Test
+ public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
+ mProvisionedListener.onDeviceProvisionedChanged();
+ verify(mEntryManager).updateNotifications();
+ }
+
+ @Test
+ public void testAppOps_appOpAddedToForegroundNotif() {
+ // GIVEN a notification associated with a foreground service
+ final NotificationEntry entry = buildEntry();
+ mNotificationData.add(entry);
+ when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+ .thenReturn(entry.key);
+
+ // WHEN we are notified of a new app op
+ mController.updateNotificationsForAppOp(
+ AppOpsManager.OP_CAMERA,
+ entry.notification.getUid(),
+ entry.notification.getPackageName(),
+ true);
+
+ // THEN the app op is added to the entry
+ assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+ // THEN updateNotifications() is called
+ verify(mEntryManager, times(1)).updateNotifications();
+ }
+
+ @Test
+ public void testAppOps_appOpAddedToUnrelatedNotif() {
+ // GIVEN No current foreground notifs
+ when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+ .thenReturn(null);
+
+ // WHEN An unrelated notification gets a new app op
+ mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+
+ // THEN We never call updateNotifications()
+ verify(mEntryManager, never()).updateNotifications();
+ }
+
+ @Test
+ public void testAppOps_addNotificationWithExistingAppOps() {
+ // GIVEN a notification with three associated app ops that is associated with a foreground
+ // service
+ final NotificationEntry entry = buildEntry();
+ mNotificationData.add(entry);
+ ArraySet<Integer> expected = new ArraySet<>();
+ expected.add(3);
+ expected.add(235);
+ expected.add(1);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn(entry.key);
+ when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn(expected);
+
+ // WHEN the notification is added
+ mEntryListener.onBeforeNotificationAdded(entry);
+
+ // THEN the entry is tagged with all three app ops
+ assertEquals(expected.size(), entry.mActiveAppOps.size());
+ for (int op : expected) {
+ assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op));
+ }
+ }
+
+ @Test
+ public void testAdd_addNotificationWithNoExistingAppOps() {
+ // GIVEN a notification with NO associated app ops
+ final NotificationEntry entry = buildEntry();
+
+ mNotificationData.add(entry);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn(entry.key);
+ when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn(null);
+
+ // WHEN the notification is added
+ mEntryListener.onBeforeNotificationAdded(entry);
+
+ // THEN the entry doesn't have any app ops associated with it
+ assertEquals(0, entry.mActiveAppOps.size());
+ }
+
+ @Test
+ public void testAdd_addNonForegroundNotificationWithExistingAppOps() {
+ // GIVEN a notification with app ops that isn't associated with a foreground service
+ final NotificationEntry entry = buildEntry();
+ mNotificationData.add(entry);
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(3);
+ ops.add(235);
+ ops.add(1);
+ when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn(ops);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ entry.notification.getUserId(),
+ entry.notification.getPackageName())).thenReturn("something else");
+
+ // WHEN the notification is added
+ mEntryListener.onBeforeNotificationAdded(entry);
+
+ // THEN the entry doesn't have any app ops associated with it
+ assertEquals(0, entry.mActiveAppOps.size());
+ }
+
+ private NotificationEntry buildEntry() {
+ mNextNotifId++;
+
+ Notification.Builder n = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+
+ StatusBarNotification notification =
+ new StatusBarNotification(
+ TEST_PACKAGE_NAME,
+ TEST_PACKAGE_NAME,
+ mNextNotifId,
+ null,
+ TEST_UID,
+ 0,
+ n.build(),
+ new UserHandle(ActivityManager.getCurrentUser()),
+ null,
+ 0);
+ return new NotificationEntry(notification);
+ }
+
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index cf9f233b8fe2..8ffaddefd3ef 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -462,7 +462,7 @@ class TouchExplorer extends BaseEventStreamTransformation
return false;
}
- endGestureDetection();
+ endGestureDetection(true);
mAms.onGesture(gestureId);
@@ -472,7 +472,7 @@ class TouchExplorer extends BaseEventStreamTransformation
@Override
public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
if (mCurrentState == STATE_GESTURE_DETECTING) {
- endGestureDetection();
+ endGestureDetection(event.getActionMasked() == MotionEvent.ACTION_UP);
return true;
} else if (mCurrentState == STATE_TOUCH_EXPLORING) {
// If the finger is still moving, pass the event on.
@@ -804,13 +804,19 @@ class TouchExplorer extends BaseEventStreamTransformation
}
}
- private void endGestureDetection() {
+ private void endGestureDetection(boolean interactionEnd) {
mAms.onTouchInteractionEnd();
// Announce the end of the gesture recognition.
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
- // Announce the end of a the touch interaction.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+ if (interactionEnd) {
+ // Announce the end of a the touch interaction.
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+ } else {
+ // If gesture detection is end, but user doesn't release the finger, announce the
+ // transition to exploration state.
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+ }
mExitGestureDetectionModeDelayed.cancel();
mCurrentState = STATE_TOUCH_EXPLORING;
@@ -889,7 +895,6 @@ class TouchExplorer extends BaseEventStreamTransformation
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
}
}
@@ -1148,8 +1153,8 @@ class TouchExplorer extends BaseEventStreamTransformation
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
// Clearing puts is in touch exploration state with a finger already
// down, so announce the transition to exploration state.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
clear();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ecc3d2da8226..174ecfa12ee6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -116,6 +116,7 @@ public abstract class BiometricServiceBase extends SystemService
protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
// Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+ protected int mHALDeathCount;
protected class PerformanceStats {
public int accept; // number of accepted biometrics
@@ -596,6 +597,7 @@ public abstract class BiometricServiceBase extends SystemService
public void serviceDied(long cookie) {
Slog.e(getTag(), "HAL died");
mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+ mHALDeathCount++;
handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /*vendorCode */);
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 5a9c1aca081a..a2aacdde4d9f 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -675,6 +675,12 @@ public class FaceService extends BiometricServiceBase {
}
@Override
+ public void serviceDied(long cookie) {
+ super.serviceDied(cookie);
+ mDaemon = null;
+ }
+
+ @Override
protected void updateActiveGroup(int userId, String clientPackage) {
IBiometricsFace daemon = getFaceDaemon();
@@ -864,6 +870,8 @@ public class FaceService extends BiometricServiceBase {
Slog.e(TAG, "dump formatting failure", e);
}
pw.println(dump);
+ pw.println("HAL Deaths: " + mHALDeathCount);
+ mHALDeathCount = 0;
}
private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 1613dc97225b..3db6a74a1c6c 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -777,6 +777,12 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
+ public void serviceDied(long cookie) {
+ super.serviceDied(cookie);
+ mDaemon = null;
+ }
+
+ @Override
protected void updateActiveGroup(int userId, String clientPackage) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
@@ -1074,6 +1080,8 @@ public class FingerprintService extends BiometricServiceBase {
Slog.e(TAG, "dump formatting failure", e);
}
pw.println(dump);
+ pw.println("HAL Deaths: " + mHALDeathCount);
+ mHALDeathCount = 0;
}
private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810f2d76..97896889f243 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@ public class PacManager {
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
+ return;
}
try {
mProxyService.setPacFile(script);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index eb4e662b2c82..414f6bbfb995 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -56,11 +56,6 @@ abstract class HdmiCecLocalDevice {
// Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
// When it expires, we can assume <User Control Release> is received.
private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
- /**
- * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
- */
- private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
- private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
protected final HdmiControlService mService;
protected final int mDeviceType;
@@ -1061,47 +1056,6 @@ abstract class HdmiCecLocalDevice {
pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
}
- /**
- * Method to parse target physical address to the port number on the current device.
- *
- * <p>This check assumes target address is valid.
- * @param targetPhysicalAddress is the physical address of the target device
- * @return
- * If the target device is under the current device, return the port number of current device
- * that the target device is connected to.
- *
- * <p>If the target device has the same physical address as the current device, return
- * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
- *
- * <p>If the target device is not under the current device, return
- * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
- */
- protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) {
- int myPhysicalAddress = mService.getPhysicalAddress();
- if (myPhysicalAddress == targetPhysicalAddress) {
- return TARGET_SAME_PHYSICAL_ADDRESS;
- }
- int finalMask = 0xF000;
- int mask;
- int port = 0;
- for (mask = 0x0F00; mask > 0x000F; mask >>= 4) {
- if ((myPhysicalAddress & mask) == 0) {
- port = mask & targetPhysicalAddress;
- break;
- } else {
- finalMask |= mask;
- }
- }
- if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) {
- while (mask != 0x000F) {
- mask >>= 4;
- port >>= 4;
- }
- return port;
- }
- return TARGET_NOT_UNDER_LOCAL_DEVICE;
- }
-
/** Calculates the physical address for {@code activePortId}.
*
* <p>This method assumes current device physical address is valid.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 71075f3d71ce..63214ed651b9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -41,7 +41,15 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -105,6 +113,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
}
+ private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
+
/**
* Called when a device is newly added or a new device is detected or
* an existing device is updated.
@@ -258,7 +268,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mTvSystemAudioModeSupport = false;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
- SystemProperties.set(
+ mService.writeStringSetting(
Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
mSystemAudioActivated ? "true" : "false");
}
@@ -320,7 +330,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
@ServiceThreadOnly
protected void setPreferredAddress(int addr) {
assertRunOnServiceThread();
- SystemProperties.set(
+ mService.writeStringSetting(
Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, String.valueOf(addr));
}
@@ -459,7 +469,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
assertRunOnServiceThread();
removeAction(ArcInitiationActionFromAvr.class);
- if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+ if (!mService.readBooleanSetting(Constants.PROPERTY_ARC_SUPPORT, true)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
} else if (!isDirectConnectToTv()) {
HdmiLogger.debug("AVR device is not directly connected with TV");
@@ -498,13 +508,35 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
return true;
}
- AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
- if (deviceInfo == null) {
- mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
- return true;
+
+ List<DeviceConfig> config = null;
+ File file = new File(SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH);
+ if (file.exists()) {
+ try {
+ InputStream in = new FileInputStream(file);
+ config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(in);
+ in.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading file: " + file, e);
+ } catch (XmlPullParserException e) {
+ Slog.e(TAG, "Unable to parse file: " + file, e);
+ }
}
+
@AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams());
- byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+ byte[] sadBytes;
+ if (config != null && config.size() > 0) {
+ sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioFormatCodes);
+ } else {
+ AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
+ if (deviceInfo == null) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
+ return true;
+ }
+
+ sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+ }
+
if (sadBytes.length == 0) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND);
} else {
@@ -531,6 +563,42 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
}
}
+ return getShortAudioDescriptorBytes(sads);
+ }
+
+ private byte[] getSupportedShortAudioDescriptorsFromConfig(
+ List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
+ DeviceConfig deviceConfigToUse = null;
+ for (DeviceConfig device : deviceConfig) {
+ // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+ if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+ deviceConfigToUse = device;
+ break;
+ }
+ }
+ if (deviceConfigToUse == null) {
+ // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+ Slog.w(TAG, "sadConfig.xml does not have required device info for "
+ + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+ return new byte[0];
+ }
+ HashMap<Integer, byte[]> map = new HashMap<>();
+ ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+ for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) {
+ map.put(codecSad.audioCodec, codecSad.sad);
+ }
+ for (int i = 0; i < audioFormatCodes.length; i++) {
+ if (map.containsKey(audioFormatCodes[i])) {
+ byte[] sad = map.get(audioFormatCodes[i]);
+ if (sad != null && sad.length == 3) {
+ sads.add(sad);
+ }
+ }
+ }
+ return getShortAudioDescriptorBytes(sads);
+ }
+
+ private byte[] getShortAudioDescriptorBytes(ArrayList<byte[]> sads) {
// Short Audio Descriptors are always 3 bytes long.
byte[] bytes = new byte[sads.size() * 3];
int index = 0;
@@ -761,7 +829,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
boolean currentMuteStatus =
mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
if (currentMuteStatus == newSystemAudioMode) {
- if (SystemProperties.getBoolean(
+ if (mService.readBooleanSetting(
Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
|| newSystemAudioMode) {
mService.getAudioManager()
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 32288de15a00..7a0c27906122 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -100,7 +100,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
@ServiceThreadOnly
protected void setPreferredAddress(int addr) {
assertRunOnServiceThread();
- SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
+ mService.writeStringSetting(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
String.valueOf(addr));
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 486faf3e9fa5..46219d5cbe8a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -646,6 +646,7 @@ public class HdmiControlService extends SystemService {
return enabled ? ENABLED : DISABLED;
}
+ @VisibleForTesting
boolean readBooleanSetting(String key, boolean defVal) {
ContentResolver cr = getContext().getContentResolver();
return Global.getInt(cr, key, toInt(defVal)) == ENABLED;
@@ -656,6 +657,11 @@ public class HdmiControlService extends SystemService {
Global.putInt(cr, key, toInt(value));
}
+ void writeStringSetting(String key, String value) {
+ ContentResolver cr = getContext().getContentResolver();
+ Global.putString(cr, key, value);
+ }
+
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 11e557c024ce..e44f1d1522ec 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -16,23 +16,35 @@
package com.android.server.hdmi;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.AudioCodec;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-
+import java.util.Objects;
/**
* Various utilities to handle HDMI CEC messages.
*/
final class HdmiUtils {
+ private static final String TAG = "HdmiUtils";
+
private static final int[] ADDRESS_TO_TYPE = {
HdmiDeviceInfo.DEVICE_TV, // ADDR_TV
HdmiDeviceInfo.DEVICE_RECORDER, // ADDR_RECORDER_1
@@ -69,6 +81,12 @@ final class HdmiUtils {
"Secondary_TV",
};
+ /**
+ * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+ */
+ static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+ static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
private HdmiUtils() { /* cannot be instantiated */ }
/**
@@ -392,6 +410,203 @@ final class HdmiUtils {
pw.decreaseIndent();
}
+ /**
+ * Method to parse target physical address to the port number on the current device.
+ *
+ * <p>This check assumes target address is valid.
+ *
+ * @param targetPhysicalAddress is the physical address of the target device
+ * @param myPhysicalAddress is the physical address of the current device
+ * @return
+ * If the target device is under the current device, return the port number of current device
+ * that the target device is connected to. This also applies to the devices that are indirectly
+ * connected to the current device.
+ *
+ * <p>If the target device has the same physical address as the current device, return
+ * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+ *
+ * <p>If the target device is not under the current device, return
+ * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+ */
+ public static int getLocalPortFromPhysicalAddress(
+ int targetPhysicalAddress, int myPhysicalAddress) {
+ if (myPhysicalAddress == targetPhysicalAddress) {
+ return TARGET_SAME_PHYSICAL_ADDRESS;
+ }
+
+ int mask = 0xF000;
+ int finalMask = 0xF000;
+ int maskedAddress = myPhysicalAddress;
+
+ while (maskedAddress != 0) {
+ maskedAddress = myPhysicalAddress & mask;
+ finalMask |= mask;
+ mask >>= 4;
+ }
+
+ int portAddress = targetPhysicalAddress & finalMask;
+ if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+ return TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ mask <<= 4;
+ int port = portAddress & mask;
+ while ((port >> 4) != 0) {
+ port >>= 4;
+ }
+ return port;
+ }
+
+ public static class ShortAudioDescriptorXmlParser {
+ // We don't use namespaces
+ private static final String NS = null;
+
+ // return a list of devices config
+ public static List<DeviceConfig> parse(InputStream in)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readDevices(parser);
+ }
+
+ private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+
+ private static List<DeviceConfig> readDevices(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<DeviceConfig> devices = new ArrayList<>();
+
+ parser.require(XmlPullParser.START_TAG, NS, "config");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the device tag
+ if (name.equals("device")) {
+ String deviceType = parser.getAttributeValue(null, "type");
+ DeviceConfig config = null;
+ if (deviceType != null) {
+ config = readDeviceConfig(parser, deviceType);
+ }
+ if (config != null) {
+ devices.add(config);
+ }
+ } else {
+ skip(parser);
+ }
+ }
+ return devices;
+ }
+
+ // Processes device tags in the config.
+ @Nullable
+ private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+ throws XmlPullParserException, IOException {
+ List<CodecSad> codecSads = new ArrayList<>();
+ int format;
+ byte[] descriptor;
+
+ parser.require(XmlPullParser.START_TAG, NS, "device");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String tagName = parser.getName();
+
+ // Starts by looking for the supportedFormat tag
+ if (tagName.equals("supportedFormat")) {
+ String codecAttriValue = parser.getAttributeValue(null, "format");
+ String sadAttriValue = parser.getAttributeValue(null, "descriptor");
+ format = (codecAttriValue) == null
+ ? Constants.AUDIO_CODEC_NONE : formatNameToNum(codecAttriValue);
+ descriptor = readSad(sadAttriValue);
+ if (format != Constants.AUDIO_CODEC_NONE && descriptor != null) {
+ codecSads.add(new CodecSad(format, descriptor));
+ }
+ parser.nextTag();
+ parser.require(XmlPullParser.END_TAG, NS, "supportedFormat");
+ } else {
+ skip(parser);
+ }
+ }
+ if (codecSads.size() == 0) {
+ return null;
+ }
+ return new DeviceConfig(deviceType, codecSads);
+ }
+
+ // Processes sad attribute in the supportedFormat.
+ @Nullable
+ private static byte[] readSad(String sad) {
+ if (sad == null || sad.length() == 0) {
+ return null;
+ }
+ byte[] sadBytes = HexDump.hexStringToByteArray(sad);
+ if (sadBytes.length != 3) {
+ Slog.w(TAG, "SAD byte array length is not 3. Length = " + sadBytes.length);
+ return null;
+ }
+ return sadBytes;
+ }
+
+ @AudioCodec
+ private static int formatNameToNum(String codecAttriValue) {
+ switch (codecAttriValue) {
+ case "AUDIO_FORMAT_NONE":
+ return Constants.AUDIO_CODEC_NONE;
+ case "AUDIO_FORMAT_LPCM":
+ return Constants.AUDIO_CODEC_LPCM;
+ case "AUDIO_FORMAT_DD":
+ return Constants.AUDIO_CODEC_DD;
+ case "AUDIO_FORMAT_MPEG1":
+ return Constants.AUDIO_CODEC_MPEG1;
+ case "AUDIO_FORMAT_MP3":
+ return Constants.AUDIO_CODEC_MP3;
+ case "AUDIO_FORMAT_MPEG2":
+ return Constants.AUDIO_CODEC_MPEG2;
+ case "AUDIO_FORMAT_AAC":
+ return Constants.AUDIO_CODEC_AAC;
+ case "AUDIO_FORMAT_DTS":
+ return Constants.AUDIO_CODEC_DTS;
+ case "AUDIO_FORMAT_ATRAC":
+ return Constants.AUDIO_CODEC_ATRAC;
+ case "AUDIO_FORMAT_ONEBITAUDIO":
+ return Constants.AUDIO_CODEC_ONEBITAUDIO;
+ case "AUDIO_FORMAT_DDP":
+ return Constants.AUDIO_CODEC_DDP;
+ case "AUDIO_FORMAT_DTSHD":
+ return Constants.AUDIO_CODEC_DTSHD;
+ case "AUDIO_FORMAT_TRUEHD":
+ return Constants.AUDIO_CODEC_TRUEHD;
+ case "AUDIO_FORMAT_DST":
+ return Constants.AUDIO_CODEC_DST;
+ case "AUDIO_FORMAT_WMAPRO":
+ return Constants.AUDIO_CODEC_WMAPRO;
+ case "AUDIO_FORMAT_MAX":
+ return Constants.AUDIO_CODEC_MAX;
+ default:
+ return Constants.AUDIO_CODEC_NONE;
+ }
+ }
+ }
+
// Device configuration of its supported Codecs and their Short Audio Descriptors.
public static class DeviceConfig {
/** Name of the device. Should be {@link Constants.AudioDevice}. **/
@@ -399,10 +614,27 @@ final class HdmiUtils {
/** List of a {@link CodecSad}. **/
public final List<CodecSad> supportedCodecs;
- private DeviceConfig(String name, List<CodecSad> supportedCodecs) {
+ public DeviceConfig(String name, List<CodecSad> supportedCodecs) {
this.name = name;
this.supportedCodecs = supportedCodecs;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof DeviceConfig) {
+ DeviceConfig that = (DeviceConfig) obj;
+ return that.name.equals(this.name)
+ && that.supportedCodecs.equals(this.supportedCodecs);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ name,
+ supportedCodecs.hashCode());
+ }
}
// Short Audio Descriptor of a specific Codec
@@ -419,5 +651,27 @@ final class HdmiUtils {
this.audioCodec = audioCodec;
this.sad = sad;
}
+
+ public CodecSad(int audioCodec, String sad) {
+ this.audioCodec = audioCodec;
+ this.sad = HexDump.hexStringToByteArray(sad);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CodecSad) {
+ CodecSad that = (CodecSad) obj;
+ return that.audioCodec == this.audioCodec
+ && Arrays.equals(that.sad, this.sad);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ audioCodec,
+ Arrays.hashCode(sad));
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6baf12ce3b44..70ead41853d0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1342,6 +1342,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mSystemTextClassifierPackage;
final @Nullable String mWellbeingPackage;
final @Nullable String mDocumenterPackage;
+ final @Nullable String mConfiguratorPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2865,6 +2866,8 @@ public class PackageManagerService extends IPackageManager.Stub
mWellbeingPackage = getWellbeingPackageName();
mDocumenterPackage = getDocumenterPackageName();
+ mConfiguratorPackage =
+ mContext.getString(R.string.config_deviceConfiguratorPackageName);
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -23122,6 +23125,8 @@ public class PackageManagerService extends IPackageManager.Stub
return mWellbeingPackage;
case PackageManagerInternal.PACKAGE_DOCUMENTER:
return mDocumenterPackage;
+ case PackageManagerInternal.PACKAGE_CONFIGURATOR:
+ return mConfiguratorPackage;
}
return null;
}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 3a49412357d8..17f83479a3b1 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -247,6 +247,10 @@ public final class BasePermission {
public boolean isDocumenter() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
}
+ public boolean isConfigurator() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
+ != 0;
+ }
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 93964cb09ae6..30b5e49bc3fd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1640,6 +1640,13 @@ public class PermissionManagerService {
// Special permissions for the system default text classifier.
allowed = true;
}
+ if (!allowed && bp.isConfigurator()
+ && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_CONFIGURATOR,
+ UserHandle.USER_SYSTEM))) {
+ // Special permissions for the device configurator.
+ allowed = true;
+ }
if (!allowed && bp.isWellbeing()
&& pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4bc241665023..6b111a0fa4fb 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -480,6 +480,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mShortPressOnSleepBehavior;
int mShortPressOnWindowBehavior;
boolean mHasSoftInput = false;
+ boolean mHapticTextHandleEnabled;
boolean mUseTvRouting;
int mVeryLongPressTimeout;
boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
@@ -567,6 +568,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
+ private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
+ private volatile boolean mMovingDisplayToTopKeyTriggered;
+ private volatile long mMovingDisplayToTopKeyTime;
+
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -606,7 +611,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mAodShowing;
private boolean mPerDisplayFocusEnabled = false;
- private int mTopFocusedDisplayId = INVALID_DISPLAY;
+ private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -634,6 +639,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
private static final int MSG_RINGER_TOGGLE_CHORD = 27;
+ private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
private class PolicyHandler extends Handler {
@Override
@@ -729,6 +735,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
+ case MSG_MOVE_DISPLAY_TO_TOP:
+ mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
+ mMovingDisplayToTopKeyTriggered = false;
+ break;
}
}
}
@@ -1827,6 +1837,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
+ mHapticTextHandleEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableHapticTextHandle);
+
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
mHandleVolumeKeysInWM = mContext.getResources().getBoolean(
@@ -2570,12 +2583,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final int eventDisplayId = event.getDisplayId();
if (result == 0 && !mPerDisplayFocusEnabled
&& eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
- // Someone tries to send a key event to a display which doesn't have a focused window.
- // We drop the event here, or it will cause ANR.
- // TODO (b/121057974): The user may be confused about why the key doesn't work, so we
- // may need to deal with this problem.
- Slog.i(TAG, "Dropping this event targeting display #" + eventDisplayId
- + " because the focus is on display #" + mTopFocusedDisplayId);
+ // An event is targeting a non-focused display. Try to move the display to top so that
+ // it can become the focused display to interact with the user.
+ final long eventDownTime = event.getDownTime();
+ if (mMovingDisplayToTopKeyTime < eventDownTime) {
+ // We have not handled this event yet. Move the display to top, and then tell
+ // dispatcher to try again later.
+ mMovingDisplayToTopKeyTime = eventDownTime;
+ mMovingDisplayToTopKeyTriggered = true;
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
+ return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+ } else if (mMovingDisplayToTopKeyTriggered) {
+ // The message has not been handled yet. Tell dispatcher to try again later.
+ return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+ }
+ // The target display is still not the top focused display. Drop the event because the
+ // display may not contain any window which can receive keys.
+ Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
+ + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
return -1;
}
return result;
@@ -5179,8 +5205,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case HapticFeedbackConstants.CLOCK_TICK:
case HapticFeedbackConstants.CONTEXT_CLICK:
return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
- case HapticFeedbackConstants.KEYBOARD_RELEASE:
case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
+ if (!mHapticTextHandleEnabled) {
+ return null;
+ }
+ case HapticFeedbackConstants.KEYBOARD_RELEASE:
case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
case HapticFeedbackConstants.ENTRY_BUMP:
case HapticFeedbackConstants.DRAG_CROSSING:
@@ -5345,11 +5374,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup);
pw.print(prefix);
pw.print("mHasSoftInput="); pw.print(mHasSoftInput);
- pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed);
+ pw.print(" mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled);
+ pw.print(prefix);
+ pw.print("mDismissImeOnBackKeyPressed="); pw.print(mDismissImeOnBackKeyPressed);
+ pw.print(" mIncallPowerBehavior=");
+ pw.println(incallPowerBehaviorToString(mIncallPowerBehavior));
pw.print(prefix);
- pw.print("mIncallPowerBehavior=");
- pw.print(incallPowerBehaviorToString(mIncallPowerBehavior));
- pw.print(" mIncallBackBehavior=");
+ pw.print("mIncallBackBehavior=");
pw.print(incallBackBehaviorToString(mIncallBackBehavior));
pw.print(" mEndcallBehavior=");
pw.println(endcallBehaviorToString(mEndcallBehavior));
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3da325c55b32..c37254b22ea5 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -634,6 +634,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* Notifies window manager that user is switched.
*/
void onUserSwitched();
+
+ /**
+ * Hint to window manager that the user is interacting with a display that should be treated
+ * as the top display.
+ */
+ void moveDisplayToTop(int displayId);
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 06168461ca1e..65d66f44b5dd 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -625,6 +625,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
return;
}
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
for (int j = windowingModes.length - 1 ; j >= 0; --j) {
final int windowingMode = windowingModes[j];
for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -635,9 +639,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
if (stack.getWindowingMode() != windowingMode) {
continue;
}
- mRootActivityContainer.mStackSupervisor.removeStack(stack);
+ stacks.add(stack);
}
}
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
}
void removeStacksWithActivityTypes(int... activityTypes) {
@@ -645,15 +653,23 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
return;
}
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
for (int j = activityTypes.length - 1 ; j >= 0; --j) {
final int activityType = activityTypes[j];
for (int i = mStacks.size() - 1; i >= 0; --i) {
final ActivityStack stack = mStacks.get(i);
if (stack.getActivityType() == activityType) {
- mRootActivityContainer.mStackSupervisor.removeStack(stack);
+ stacks.add(stack);
}
}
}
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
}
void onStackWindowingModeChanged(ActivityStack stack) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a4cda5aac895..3a288ca5560d 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2641,6 +2641,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
try {
mService.moveTaskToFrontLocked(task.taskId, 0, options,
true /* fromRecents */);
+ // Apply options to prevent pendingOptions be taken by client to make sure
+ // the override pending app transition will be applied immediately.
+ targetActivity.applyOptionsLocked();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
targetActivity);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 937c9d9fc809..58cf73a9a2bd 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -47,10 +47,9 @@ import android.view.IWindowId;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
-import android.view.Surface;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import android.view.InsetsState;
import android.view.WindowManager;
import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -432,7 +431,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void insetsModified(IWindow window, InsetsState state) {
- synchronized (mService.mWindowMap) {
+ synchronized (mService.mGlobalLock) {
final WindowState windowState = mService.windowForClientLocked(this, window,
false /* throwOnError */);
if (windowState != null) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index b2194190f4f4..905787051de8 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -67,7 +67,7 @@ public class TaskTapPointerEventListener implements PointerEventListener {
return;
}
WindowContainer parent = mDisplayContent.getParent();
- if (parent != null) {
+ if (parent != null && parent.getTopChild() != mDisplayContent) {
parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
true /* includingParents */);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 25e61f876722..19058776d187 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -437,6 +437,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
if (mChildren.peekLast() != child) {
mChildren.remove(child);
mChildren.add(child);
+ onChildPositionChanged();
}
if (includingParents && getParent() != null) {
getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -447,6 +448,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
if (mChildren.peekFirst() != child) {
mChildren.remove(child);
mChildren.addFirst(child);
+ onChildPositionChanged();
}
if (includingParents && getParent() != null) {
getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -460,8 +462,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// doing this adjustment here and remove any adjustments in the callers.
mChildren.remove(child);
mChildren.add(position, child);
+ onChildPositionChanged();
}
- onChildPositionChanged();
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 90506e744250..0c4f4961d215 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -723,7 +723,7 @@ public class WindowManagerService extends IWindowManager.Stub
void updateSystemUiSettings() {
boolean changed;
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
|| PolicyControl.reloadFromSetting(mContext);
}
@@ -2629,12 +2629,23 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void onUserSwitched() {
mSettingsObserver.updateSystemUiSettings();
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
}
}
+ @Override
+ public void moveDisplayToTop(int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null && mRoot.getTopChild() != displayContent) {
+ mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+ true /* includingParents */);
+ }
+ }
+ }
+
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
@@ -6379,7 +6390,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
- synchronized (mWindowMap) {
+ synchronized (mGlobalLock) {
mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
}
}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 000000000000..5b77f543c62b
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+ /**
+ * Convert a ProxyInfo to a ProxyInfoParcelable
+ */
+ public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+ if (proxyInfo == null) {
+ return null;
+ }
+ final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+ parcel.host = proxyInfo.getHost();
+ parcel.port = proxyInfo.getPort();
+ parcel.exclusionList = proxyInfo.getExclusionList();
+ parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+ return parcel;
+ }
+
+ /**
+ * Convert a ProxyInfoParcelable to a ProxyInfo
+ */
+ public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+ }
+ }
+
+ /**
+ * Convert an IpPrefixParcelable to an IpPrefix
+ */
+ public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+ if (ipPrefix == null) {
+ return null;
+ }
+ final IpPrefixParcelable parcel = new IpPrefixParcelable();
+ parcel.address = ipPrefix.getAddress().getHostAddress();
+ parcel.prefixLength = ipPrefix.getPrefixLength();
+ return parcel;
+ }
+
+ /**
+ * Convert an IpPrefix to an IpPrefixParcelable
+ */
+ public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+ }
+
+ /**
+ * Convert a RouteInfoParcelable to a RouteInfo
+ */
+ public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+ if (routeInfo == null) {
+ return null;
+ }
+ final RouteInfoParcelable parcel = new RouteInfoParcelable();
+ parcel.destination = toStableParcelable(routeInfo.getDestination());
+ parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+ parcel.ifaceName = routeInfo.getInterface();
+ parcel.type = routeInfo.getType();
+ return parcel;
+ }
+
+ /**
+ * Convert a RouteInfo to a RouteInfoParcelable
+ */
+ public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final IpPrefix destination = fromStableParcelable(parcel.destination);
+ return new RouteInfo(
+ destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+ parcel.ifaceName, parcel.type);
+ }
+
+ /**
+ * Convert a LinkAddressParcelable to a LinkAddress
+ */
+ public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+ if (la == null) {
+ return null;
+ }
+ final LinkAddressParcelable parcel = new LinkAddressParcelable();
+ parcel.address = la.getAddress().getHostAddress();
+ parcel.prefixLength = la.getPrefixLength();
+ parcel.flags = la.getFlags();
+ parcel.scope = la.getScope();
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkAddress to a LinkAddressParcelable
+ */
+ public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new LinkAddress(
+ InetAddresses.parseNumericAddress(parcel.address),
+ parcel.prefixLength,
+ parcel.flags,
+ parcel.scope);
+ }
+
+ /**
+ * Convert a LinkProperties to a LinkPropertiesParcelable
+ */
+ public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+ if (lp == null) {
+ return null;
+ }
+ final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+ parcel.ifaceName = lp.getInterfaceName();
+ parcel.linkAddresses = toParcelableArray(
+ lp.getLinkAddresses(),
+ LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkAddressParcelable.class);
+ parcel.dnses = toParcelableArray(
+ lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.pcscfs = toParcelableArray(
+ lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+ parcel.validatedPrivateDnses = toParcelableArray(
+ lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.usePrivateDns = lp.isPrivateDnsActive();
+ parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+ parcel.domains = lp.getDomains();
+ parcel.routes = toParcelableArray(
+ lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+ RouteInfoParcelable.class);
+ parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+ parcel.mtu = lp.getMtu();
+ parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+ parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+ parcel.stackedLinks = toParcelableArray(
+ lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkPropertiesParcelable.class);
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkPropertiesParcelable to a LinkProperties
+ */
+ public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(parcel.ifaceName);
+ lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+ LinkPropertiesParcelableUtil::fromStableParcelable));
+ lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+ lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+ lp.setValidatedPrivateDnsServers(
+ fromParcelableArray(parcel.validatedPrivateDnses,
+ InetAddresses::parseNumericAddress));
+ lp.setUsePrivateDns(parcel.usePrivateDns);
+ lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+ lp.setDomains(parcel.domains);
+ for (RouteInfoParcelable route : parcel.routes) {
+ lp.addRoute(fromStableParcelable(route));
+ }
+ lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+ lp.setMtu(parcel.mtu);
+ lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+ lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+ for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+ lp.addStackedLink(fromStableParcelable(stackedLink));
+ }
+ return lp;
+ }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 000000000000..a18976c9eee6
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+ // Below methods could be implemented easily with streams, but streams are frowned upon in
+ // frameworks code.
+
+ /**
+ * Convert a list of BaseType items to an array of ParcelableType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+ @NonNull List<BaseType> base,
+ @NonNull Function<BaseType, ParcelableType> conv,
+ @NonNull Class<ParcelableType> parcelClass) {
+ final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+ int i = 0;
+ for (BaseType b : base) {
+ out[i] = conv.apply(b);
+ i++;
+ }
+ return out;
+ }
+
+ /**
+ * Convert an array of ParcelableType items to a list of BaseType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+ @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+ final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+ for (ParcelableType t : parceled) {
+ out.add(conv.apply(t));
+ }
+ return out;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 8b0e8abf069d..eb9b98ec65f7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -30,6 +30,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -147,6 +148,7 @@ public class ArcInitiationActionFromAvrTest {
mTestLooper.dispatchAll();
}
+ @Ignore("b/120845532")
@Test
public void arcInitiation_requestActiveSource() {
mSendCecCommandSuccess = true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index 93a09dc3ff04..5d8131f35eb7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -40,7 +40,6 @@ import androidx.test.filters.SmallTest;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -142,7 +141,6 @@ public class HdmiCecControllerTest {
assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
@@ -158,7 +156,6 @@ public class HdmiCecControllerTest {
assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 3b51a2a70f83..3a6cdc2ad7c9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -21,6 +21,7 @@ import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_UPDATE_DEVIC
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -29,9 +30,9 @@ import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
import static com.google.common.truth.Truth.assertThat;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
import android.media.AudioManager;
import android.os.Looper;
-import android.os.SystemProperties;
import android.os.test.TestLooper;
import androidx.test.InstrumentationRegistry;
@@ -46,7 +47,6 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.ArrayList;
-
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -67,9 +67,15 @@ public class HdmiCecLocalDeviceAudioSystemTest {
private int mMusicVolume;
private int mMusicMaxVolume;
private boolean mMusicMute;
- private int mAvrPhysicalAddress;
+ private static final int SELF_PHYSICAL_ADDRESS = 0x2000;
+ private static final int HDMI_1_PHYSICAL_ADDRESS = 0x2100;
+ private static final int HDMI_2_PHYSICAL_ADDRESS = 0x2200;
+ private static final int HDMI_3_PHYSICAL_ADDRESS = 0x2300;
private int mInvokeDeviceEventState;
private HdmiDeviceInfo mDeviceInfo;
+ private boolean mMutingEnabled;
+ private boolean mArcSupport;
+ private HdmiPortInfo[] mHdmiPortInfo;
@Before
public void setUp() {
@@ -141,9 +147,20 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Override
- int pathToPortId(int path) {
- // port id is not useful for the test right now
- return 1;
+ void writeStringSetting(String key, String value) {
+ // do nothing
+ }
+
+ @Override
+ boolean readBooleanSetting(String key, boolean defVal) {
+ switch (key) {
+ case Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE:
+ return mMutingEnabled;
+ case Constants.PROPERTY_ARC_SUPPORT:
+ return mArcSupport;
+ default:
+ return defVal;
+ }
}
};
@@ -154,11 +171,17 @@ public class HdmiCecLocalDeviceAudioSystemTest {
void setIsActiveSource(boolean on) {
mIsActiveSource = on;
}
+
+ @Override
+ protected int getPreferredAddress() {
+ return ADDR_PLAYBACK_1;
+ }
};
mHdmiCecLocalDeviceAudioSystem.init();
mHdmiCecLocalDevicePlayback.init();
mHdmiControlService.setIoLooper(mMyLooper);
mNativeWrapper = new FakeNativeWrapper();
+ mNativeWrapper.setPhysicalAddress(SELF_PHYSICAL_ADDRESS);
mHdmiCecController =
HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
mHdmiControlService.setCecController(mHdmiCecController);
@@ -166,15 +189,28 @@ public class HdmiCecLocalDeviceAudioSystemTest {
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+ mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnables(true);
+ mHdmiPortInfo = new HdmiPortInfo[4];
+ mHdmiPortInfo[0] =
+ new HdmiPortInfo(
+ 0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[1] =
+ new HdmiPortInfo(
+ 2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[2] =
+ new HdmiPortInfo(
+ 1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[3] =
+ new HdmiPortInfo(
+ 4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
+ mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiControlService.initPortInfo();
// No TV device interacts with AVR so system audio control won't be turned on here
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
mNativeWrapper.clearResultMessages();
- mAvrPhysicalAddress = 0x2000;
- mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress);
- SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true");
- SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "true");
+ mMutingEnabled = true;
+ mArcSupport = true;
mInvokeDeviceEventState = 0;
mDeviceInfo = null;
}
@@ -244,6 +280,8 @@ public class HdmiCecLocalDeviceAudioSystemTest {
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
+ // Testing device has sadConfig.xml
+ @Ignore("b/120845532")
@Test
public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception {
HdmiCecMessage expectedMessage =
@@ -414,51 +452,6 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void pathToPort_isMe() throws Exception {
- int targetPhysicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(0x1000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(0);
- }
-
- @Test
- public void pathToPort_isBelow() throws Exception {
- int targetPhysicalAddress = 0x1100;
- mNativeWrapper.setPhysicalAddress(0x1000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(1);
- }
-
- @Test
- public void pathToPort_neitherMeNorBelow() throws Exception {
- int targetPhysicalAddress = 0x3000;
- mNativeWrapper.setPhysicalAddress(0x2000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2200;
- mNativeWrapper.setPhysicalAddress(0x3300);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2213;
- mNativeWrapper.setPhysicalAddress(0x2212);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2340;
- mNativeWrapper.setPhysicalAddress(0x2310);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
- }
-
- @Test
public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
@@ -530,7 +523,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
ADDR_TV,
Constants.MESSAGE_REQUEST_ARC_INITIATION,
Constants.ABORT_UNRECOGNIZED_OPCODE);
- SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false");
+ mArcSupport = false;
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
mTestLooper.dispatchAll();
@@ -541,7 +534,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSystemAudioModeRequest(
ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
- mAvrPhysicalAddress, true);
+ SELF_PHYSICAL_ADDRESS, true);
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildFeatureAbortCommand(
ADDR_AUDIO_SYSTEM,
@@ -559,7 +552,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSystemAudioModeRequest(
ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
- mAvrPhysicalAddress, true);
+ SELF_PHYSICAL_ADDRESS, true);
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildSetSystemAudioMode(
ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, true);
@@ -585,15 +578,14 @@ public class HdmiCecLocalDeviceAudioSystemTest {
.isEqualTo(expectedActiveSource);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void handleRoutingChange_currentActivePortIsHome() {
HdmiCecMessage message =
- HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, mAvrPhysicalAddress);
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, SELF_PHYSICAL_ADDRESS);
HdmiCecMessage expectedMessage =
- HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
- ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
+ ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
@@ -608,17 +600,18 @@ public class HdmiCecLocalDeviceAudioSystemTest {
@Test
public void handleRoutingInformation_currentActivePortIsHDMI1() {
HdmiCecMessage message =
- HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x2000);
- mHdmiCecLocalDeviceAudioSystem.setRoutingPort(Constants.CEC_SWITCH_HDMI1);
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, SELF_PHYSICAL_ADDRESS);
+ mHdmiCecLocalDeviceAudioSystem.setRoutingPort(mHdmiPortInfo[1].getId());
HdmiCecMessage expectedMessage =
- HdmiCecMessageBuilder.buildRoutingInformation(ADDR_AUDIO_SYSTEM, 0x2100);
+ HdmiCecMessageBuilder.buildRoutingInformation(
+ ADDR_AUDIO_SYSTEM, HDMI_1_PHYSICAL_ADDRESS);
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
+ @Ignore("b/120845532")
@Test
public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
HdmiCecMessage message =
@@ -667,7 +660,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
- ADDR_PLAYBACK_1, 0x2100, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
+ ADDR_PLAYBACK_1, 0x2300, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
mHdmiCecLocalDeviceAudioSystem.updateCecDevice(differentDevice);
@@ -686,14 +679,13 @@ public class HdmiCecLocalDeviceAudioSystemTest {
mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
- ADDR_PLAYBACK_1, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
- Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+ ADDR_PLAYBACK_2, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
+ Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_2));
HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
.buildReportPhysicalAddressCommand(
- ADDR_PLAYBACK_1, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ ADDR_PLAYBACK_2, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
mHdmiCecLocalDeviceAudioSystem.handleReportPhysicalAddress(reportPhysicalAddress);
- mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
mTestLooper.dispatchAll();
assertThat(mDeviceInfo).isEqualTo(differentDevice);
assertThat(mHdmiCecLocalDeviceAudioSystem
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 792c617b99ea..feae4eed7eb1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -81,7 +81,8 @@ public class HdmiCecLocalDevicePlaybackTest {
mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
}
- @Ignore
+ // Playback device does not handle routing control related feature right now
+ @Ignore("b/120845532")
@Test
public void handleSetStreamPath_underCurrentDevice() {
assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 67ce13fdef72..1f660742122d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -179,6 +179,7 @@ public class HdmiControlServiceTest {
@Test
public void pathToPort_pathExists_weAreNonTv() {
mNativeWrapper.setPhysicalAddress(0x2000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(1);
assertThat(mHdmiControlService.pathToPortId(0x2234)).isEqualTo(2);
}
@@ -186,6 +187,7 @@ public class HdmiControlServiceTest {
@Test
public void pathToPort_pathExists_weAreTv() {
mNativeWrapper.setPhysicalAddress(0x0000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(3);
assertThat(mHdmiControlService.pathToPortId(0x3234)).isEqualTo(4);
}
@@ -193,6 +195,7 @@ public class HdmiControlServiceTest {
@Test
public void pathToPort_pathInvalid() {
mNativeWrapper.setPhysicalAddress(0x2000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x1000)).isEqualTo(Constants.INVALID_PORT_ID);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
new file mode 100644
index 000000000000..985c6476d767
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.server.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+ private static final String TAG = "HdmiUtilsTest";
+
+ private final String mExampleXML =
+ "<!-- A sample Short Audio Descriptor configuration xml -->"
+ + "<config version=\"1.0\" xmlns:xi=\"http://www.w3.org/2001/XInclude\">"
+ + "<device type=\"VX_AUDIO_DEVICE_IN_HDMI_ARC\">"
+ + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"011a03\"/>"
+ + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"0d0506\"/>"
+ + "</device>"
+ + "<device type=\"AUDIO_DEVICE_IN_SPDIF\">"
+ + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"010203\"/>"
+ + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"040506\"/>"
+ + "</device>"
+ + "</config>";
+
+ @Test
+ public void pathToPort_isMe() {
+ int targetPhysicalAddress = 0x1000;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+ }
+
+ @Test
+ public void pathToPort_isDirectlyBelow() {
+ int targetPhysicalAddress = 0x1100;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_isBelow() {
+ int targetPhysicalAddress = 0x1110;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_neitherMeNorBelow() {
+ int targetPhysicalAddress = 0x3000;
+ int myPhysicalAddress = 0x2000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2200;
+ myPhysicalAddress = 0x3300;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2213;
+ myPhysicalAddress = 0x2212;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2340;
+ myPhysicalAddress = 0x2310;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+ }
+
+ @Test
+ public void parseSampleXML() {
+ List<DeviceConfig> config = new ArrayList<>();
+ try {
+ config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(
+ new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
+ } catch (IOException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ } catch (XmlPullParserException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ }
+
+ CodecSad expectedCodec1 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "011a03");
+ CodecSad expectedCodec2 = new CodecSad(Constants.AUDIO_CODEC_DD, "0d0506");
+ CodecSad expectedCodec3 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "010203");
+ CodecSad expectedCodec4 = new CodecSad(Constants.AUDIO_CODEC_DD, "040506");
+
+ List<CodecSad> expectedList1 = new ArrayList<>();
+ expectedList1.add(expectedCodec1);
+ expectedList1.add(expectedCodec2);
+
+ List<CodecSad> expectedList2 = new ArrayList<>();
+ expectedList2.add(expectedCodec3);
+ expectedList2.add(expectedCodec4);
+
+ DeviceConfig expectedDevice1 = new DeviceConfig(
+ "VX_AUDIO_DEVICE_IN_HDMI_ARC", expectedList1);
+ DeviceConfig expectedDevice2 = new DeviceConfig(
+ "AUDIO_DEVICE_IN_SPDIF", expectedList2);
+
+ List<DeviceConfig> expectedConfig = new ArrayList<>();
+ expectedConfig.add(expectedDevice1);
+ expectedConfig.add(expectedDevice2);
+
+ assertThat(config).isEqualTo(expectedConfig);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index bd297eecf25c..440a49ab81fc 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -31,6 +31,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -150,6 +151,11 @@ public class SystemAudioInitiationActionFromAvrTest {
int sourceAddress, int physicalAddress) {
mBroadcastActiveSource = true;
}
+
+ @Override
+ int pathToPortId(int path) {
+ return -1;
+ }
};
mHdmiCecLocalDeviceAudioSystem =
new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -270,6 +276,7 @@ public class SystemAudioInitiationActionFromAvrTest {
assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
}
+ @Ignore("b/120845532")
@Test
public void testIsPlaybackDevice_cannotReceiveActiveSource() {
resetTestVariables();
@@ -282,10 +289,10 @@ public class SystemAudioInitiationActionFromAvrTest {
mTestLooper.dispatchAll();
assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
- assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+ assertThat(mBroadcastActiveSource).isTrue();
assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+ assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
- assertThat(mBroadcastActiveSource).isTrue();
}
private void resetTestVariables() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5bf3d2dabe24..f947baceafd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -36,6 +36,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import android.platform.test.annotations.Presubmit;
@@ -277,4 +280,60 @@ public class ActivityDisplayTests extends ActivityTestsBase {
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
}
+
+ @Test
+ public void testRemoveStackInWindowingModes() {
+ removeStackTests(() -> mRootActivityContainer.removeStacksInWindowingModes(
+ WINDOWING_MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void testRemoveStackWithActivityTypes() {
+ removeStackTests(
+ () -> mRootActivityContainer.removeStacksWithActivityTypes(ACTIVITY_TYPE_STANDARD));
+ }
+
+ private void removeStackTests(Runnable runnable) {
+ final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+ final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
+ stack1).setTaskId(1).build();
+ final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
+ stack2).setTaskId(2).build();
+ final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
+ stack3).setTaskId(3).build();
+ final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
+ stack4).setTaskId(4).build();
+
+ // Reordering stacks while removing stacks.
+ doAnswer(invocation -> {
+ display.positionChildAtTop(stack3, false);
+ return true;
+ }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+ any());
+
+ // Removing stacks from the display while removing stacks.
+ doAnswer(invocation -> {
+ display.removeChild(stack2);
+ return true;
+ }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+ any());
+
+ runnable.run();
+ verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+ any());
+ verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
+ any());
+ verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+ any());
+ verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
+ any());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 1c33dfb79551..99be50be642e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -314,13 +314,11 @@ public class TaskRecordTests extends ActivityTestsBase {
// Wire up task and stack.
task.mTask.mTaskRecord = task;
doCallRealMethod().when(task.mTask).onDescendantOrientationChanged(any(), any());
- doReturn(stack.getWindowContainerController().mContainer).when(task.mTask).getParent();
+ doReturn(stack.getTaskStack()).when(task.mTask).getParent();
// Wire up stack and display content.
- doCallRealMethod().when(stack.mWindowContainerController.mContainer)
- .onDescendantOrientationChanged(any(), any());
- doReturn(display.mDisplayContent).when(stack.mWindowContainerController.mContainer)
- .getParent();
+ doCallRealMethod().when(stack.mTaskStack).onDescendantOrientationChanged(any(), any());
+ doReturn(display.mDisplayContent).when(stack.mTaskStack).getParent();
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertTrue("Bounds of the task should be pillarboxed.",
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 3408291825d1..17516bc24aca 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -66,7 +66,8 @@ public class DctConstants {
public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
public static final int EVENT_ROAMING_ON = BASE + 11;
public static final int EVENT_ROAMING_OFF = BASE + 12;
- public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+ public static final int EVENT_ENABLE_APN = BASE + 13;
+ public static final int EVENT_DISABLE_APN = BASE + 14;
public static final int EVENT_DISCONNECT_DONE = BASE + 15;
public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 000000000000..4cabfc95b49d
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+ private LinkProperties mLinkProperties;
+
+ private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+ private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+ private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+ @Before
+ public void setUp() {
+ mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+ }
+
+ private static LinkProperties makeLinkProperties(String iface) {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(iface);
+ lp.setLinkAddresses(Arrays.asList(
+ new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+ lp.setDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::42"),
+ InetAddresses.parseNumericAddress("192.168.1.1")
+ ));
+ lp.setValidatedPrivateDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::43"),
+ InetAddresses.parseNumericAddress("192.168.42.43")
+ ));
+ lp.setPcscfServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::47"),
+ InetAddresses.parseNumericAddress("192.168.42.47")
+ ));
+ lp.setUsePrivateDns(true);
+ lp.setPrivateDnsServerName("test.example.com");
+ lp.setDomains("test1.example.com,test2.example.com");
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+ InetAddresses.parseNumericAddress("2001:db8::45"),
+ iface,
+ RouteInfo.RTN_UNICAST
+ ));
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+ InetAddresses.parseNumericAddress("192.168.45.1"),
+ iface,
+ RouteInfo.RTN_THROW
+ ));
+ lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+ "excl1.example.com,excl2.example.com"));
+ lp.setMtu(5000);
+ lp.setTcpBufferSizes("1,2,3,4,5,6");
+ lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+ // Verify that this test does not miss any new field added later.
+ // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+ // must also be updated.
+ assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+ .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+ return lp;
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullInterface() {
+ mLinkProperties.setInterfaceName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullPrivateDnsServer() {
+ mLinkProperties.setPrivateDnsServerName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullDomains() {
+ mLinkProperties.setDomains(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullProxy() {
+ mLinkProperties.setHttpProxy(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullTcpBufferSizes() {
+ mLinkProperties.setTcpBufferSizes(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyLinkAddresses() {
+ mLinkProperties.setLinkAddresses(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyDnses() {
+ mLinkProperties.setDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+ mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyRoutes() {
+ for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+ mLinkProperties.removeRoute(r);
+ }
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_PacFileProxyInfo() {
+ mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullNat64Prefix() {
+ mLinkProperties.setNat64Prefix(null);
+ doParcelUnparcelTest();
+ }
+
+ private void doParcelUnparcelTest() {
+ final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+ assertLinkPropertiesEquals(mLinkProperties, unparceled);
+ }
+
+ private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+ assertEquals(expected, actual);
+
+ // LinkProperties equals() does not include stacked links
+ assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+ }
+}