summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt25
-rw-r--r--api/system-current.txt30
-rw-r--r--api/test-current.txt25
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java48
-rw-r--r--core/java/android/content/Intent.java6
-rw-r--r--core/java/android/content/pm/SELinuxUtil.java9
-rw-r--r--core/java/android/content/res/FontResourcesParser.java5
-rw-r--r--core/java/android/metrics/LogMaker.java25
-rw-r--r--core/java/android/metrics/MetricsReader.java85
-rw-r--r--core/java/android/net/ConnectivityManager.java148
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/nfc/NdefRecord.java2
-rw-r--r--core/java/android/provider/FontsContract.java104
-rw-r--r--core/java/android/text/FontConfig.java22
-rw-r--r--core/java/android/text/Hyphenator.java113
-rw-r--r--core/java/android/text/StaticLayout.java3
-rw-r--r--core/java/android/util/Patterns.java18
-rw-r--r--core/java/android/view/IPinnedStackListener.aidl6
-rw-r--r--core/java/android/view/NotificationHeaderView.java40
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java2
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java15
-rw-r--r--core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java14
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java3
-rw-r--r--core/java/com/android/internal/logging/legacy/EventLogCollector.java173
-rw-r--r--core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java101
-rw-r--r--core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java66
-rw-r--r--core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java48
-rwxr-xr-xcore/java/com/android/internal/logging/legacy/TagParser.java104
-rw-r--r--core/java/com/android/internal/logging/legacy/TronCounters.java72
-rw-r--r--core/java/com/android/internal/logging/legacy/TronLogger.java49
-rw-r--r--core/java/com/android/internal/logging/legacy/Util.java25
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java48
-rw-r--r--core/java/com/android/internal/widget/NotificationExpandButton.java8
-rw-r--r--core/jni/android_text_StaticLayout.cpp8
-rw-r--r--core/res/res/layout/notification_template_header.xml2
-rw-r--r--core/res/res/values-television/config.xml7
-rw-r--r--core/res/res/values/attrs.xml11
-rw-r--r--core/res/res/values/config.xml14
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml7
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/coretests/res/font/samplexmldownloadedfont.xml3
-rw-r--r--core/tests/coretests/src/android/content/res/FontResourcesParserTest.java3
-rw-r--r--core/tests/coretests/src/android/metrics/LogMakerTest.java49
-rw-r--r--core/tests/coretests/src/android/provider/FontsContractTest.java235
-rw-r--r--core/tests/coretests/src/android/provider/TestFontsProvider.java117
-rw-r--r--graphics/java/android/graphics/Typeface.java4
-rw-r--r--graphics/java/android/graphics/fonts/FontRequest.java76
-rw-r--r--libs/hwui/BakedOpState.cpp16
-rw-r--r--libs/hwui/BakedOpState.h9
-rw-r--r--libs/hwui/FrameBuilder.cpp12
-rw-r--r--libs/hwui/FrameBuilder.h3
-rw-r--r--libs/hwui/tests/unit/BakedOpStateTests.cpp16
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp29
-rw-r--r--packages/SystemUI/res/drawable/pip_expand.xml38
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml21
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java191
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java107
-rw-r--r--proto/src/metrics_constants.proto31
-rw-r--r--rs/java/android/renderscript/Element.java2
-rw-r--r--rs/java/android/renderscript/Type.java1
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java20
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java92
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java8
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java53
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java10
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java1
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java6
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java78
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java55
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java14
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java52
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java69
-rw-r--r--telecomm/java/android/telecom/Call.java46
-rw-r--r--telecomm/java/android/telecom/Connection.java171
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java188
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java62
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java44
-rw-r--r--telecomm/java/android/telecom/InCallAdapter.java16
-rw-r--r--telecomm/java/android/telecom/InCallService.java15
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java9
-rw-r--r--telecomm/java/android/telecom/Phone.java17
-rw-r--r--telecomm/java/android/telecom/RemoteConnection.java146
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java52
-rw-r--r--telecomm/java/android/telecom/VideoCallImpl.java7
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl13
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl8
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl8
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallService.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/IVideoProvider.aidl2
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java28
-rw-r--r--tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java5
112 files changed, 2950 insertions, 1359 deletions
diff --git a/api/current.txt b/api/current.txt
index 8552237ba024..9d61da7f1ab5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -607,6 +607,7 @@ package android {
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int fontProviderAuthority = 16844114; // 0x1010552
+ field public static final int fontProviderPackage = 16844122; // 0x101055a
field public static final int fontProviderQuery = 16844115; // 0x1010553
field public static final int fontStyle = 16844081; // 0x1010531
field public static final int fontWeight = 16844083; // 0x1010533
@@ -2811,6 +2812,7 @@ package android.accessibilityservice {
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
+ method public java.lang.String loadSummary(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
@@ -14088,9 +14090,12 @@ package android.graphics.drawable.shapes {
package android.graphics.fonts {
public final class FontRequest implements android.os.Parcelable {
- ctor public FontRequest(java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String, java.util.List<java.util.List<byte[]>>);
method public int describeContents();
+ method public java.util.List<java.util.List<byte[]>> getCertificates();
method public java.lang.String getProviderAuthority();
+ method public java.lang.String getProviderPackage();
method public java.lang.String getQuery();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
@@ -19634,6 +19639,8 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
+ field public static final int TIMEZONE_ICU = 0; // 0x0
+ field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -24948,6 +24955,7 @@ package android.net {
method public void reportNetworkConnectivity(android.net.Network, boolean);
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
+ method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -24995,6 +25003,7 @@ package android.net {
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
+ method public void onUnavailable();
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -38198,6 +38207,7 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttInitiationFailure(android.telecom.Call, int);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
@@ -38464,6 +38474,15 @@ package android.telecom {
field public static final int STATE_RINGING = 2; // 0x2
}
+ public static final class Connection.RttModifyStatus {
+ ctor public Connection.RttModifyStatus();
+ field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+ field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+ field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
+ field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+ field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -38521,9 +38540,9 @@ package android.telecom {
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
diff --git a/api/system-current.txt b/api/system-current.txt
index 94825a390ce2..87846c0b14fd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -719,6 +719,7 @@ package android {
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int fontProviderAuthority = 16844114; // 0x1010552
+ field public static final int fontProviderPackage = 16844122; // 0x101055a
field public static final int fontProviderQuery = 16844115; // 0x1010553
field public static final int fontStyle = 16844081; // 0x1010531
field public static final int fontWeight = 16844083; // 0x1010533
@@ -2930,6 +2931,7 @@ package android.accessibilityservice {
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
+ method public java.lang.String loadSummary(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
@@ -14805,9 +14807,12 @@ package android.graphics.drawable.shapes {
package android.graphics.fonts {
public final class FontRequest implements android.os.Parcelable {
- ctor public FontRequest(java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String, java.util.List<java.util.List<byte[]>>);
method public int describeContents();
+ method public java.util.List<java.util.List<byte[]>> getCertificates();
method public java.lang.String getProviderAuthority();
+ method public java.lang.String getProviderPackage();
method public java.lang.String getQuery();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
@@ -21073,6 +21078,8 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
+ field public static final int TIMEZONE_ICU = 0; // 0x0
+ field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -26722,7 +26729,12 @@ package android.metrics {
ctor public LogMaker(int);
ctor public LogMaker(java.lang.Object[]);
method public android.metrics.LogMaker addTaggedData(int, java.lang.Object);
+ method public android.metrics.LogMaker clearCategory();
+ method public android.metrics.LogMaker clearPackageName();
+ method public android.metrics.LogMaker clearSubtype();
method public android.metrics.LogMaker clearTaggedData(int);
+ method public android.metrics.LogMaker clearTimestamp();
+ method public android.metrics.LogMaker clearType();
method public void deserialize(java.lang.Object[]);
method public int getCategory();
method public long getCounterBucket();
@@ -27041,6 +27053,7 @@ package android.net {
method public void reportNetworkConnectivity(android.net.Network, boolean);
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
+ method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -27094,6 +27107,7 @@ package android.net {
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
+ method public void onUnavailable();
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -41330,6 +41344,7 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttInitiationFailure(android.telecom.Call, int);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
@@ -41607,6 +41622,15 @@ package android.telecom {
field public static final int STATE_RINGING = 2; // 0x2
}
+ public static final class Connection.RttModifyStatus {
+ ctor public Connection.RttModifyStatus();
+ field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+ field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+ field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
+ field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+ field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -41664,9 +41688,9 @@ package android.telecom {
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
diff --git a/api/test-current.txt b/api/test-current.txt
index b92a04ec5209..cce60245ee31 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -607,6 +607,7 @@ package android {
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int fontProviderAuthority = 16844114; // 0x1010552
+ field public static final int fontProviderPackage = 16844122; // 0x101055a
field public static final int fontProviderQuery = 16844115; // 0x1010553
field public static final int fontStyle = 16844081; // 0x1010531
field public static final int fontWeight = 16844083; // 0x1010533
@@ -2811,6 +2812,7 @@ package android.accessibilityservice {
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
+ method public java.lang.String loadSummary(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
@@ -14127,9 +14129,12 @@ package android.graphics.drawable.shapes {
package android.graphics.fonts {
public final class FontRequest implements android.os.Parcelable {
- ctor public FontRequest(java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String);
+ ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String, java.util.List<java.util.List<byte[]>>);
method public int describeContents();
+ method public java.util.List<java.util.List<byte[]>> getCertificates();
method public java.lang.String getProviderAuthority();
+ method public java.lang.String getProviderPackage();
method public java.lang.String getQuery();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.graphics.fonts.FontRequest> CREATOR;
@@ -19673,6 +19678,8 @@ package android.icu.util {
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
+ field public static final int TIMEZONE_ICU = 0; // 0x0
+ field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -25045,6 +25052,7 @@ package android.net {
method public void reportNetworkConnectivity(android.net.Network, boolean);
method public boolean requestBandwidthUpdate(android.net.Network);
method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
+ method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
method public deprecated void setNetworkPreference(int);
method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
@@ -25092,6 +25100,7 @@ package android.net {
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
+ method public void onUnavailable();
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -38383,6 +38392,7 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttInitiationFailure(android.telecom.Call, int);
method public void onRttModeChanged(android.telecom.Call, int);
method public void onRttRequest(android.telecom.Call, int);
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
@@ -38649,6 +38659,15 @@ package android.telecom {
field public static final int STATE_RINGING = 2; // 0x2
}
+ public static final class Connection.RttModifyStatus {
+ ctor public Connection.RttModifyStatus();
+ field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+ field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+ field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
+ field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+ field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -38706,9 +38725,9 @@ package android.telecom {
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 19d1a7d899c9..5937dd951dc4 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -69,10 +69,10 @@ import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
* @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
* @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
* @attr ref android.R.styleable#AccessibilityService_description
+ * @attr ref android.R.styleable#AccessibilityService_summary
* @attr ref android.R.styleable#AccessibilityService_notificationTimeout
* @attr ref android.R.styleable#AccessibilityService_packageNames
* @attr ref android.R.styleable#AccessibilityService_settingsActivity
- *
* @see AccessibilityService
* @see android.view.accessibility.AccessibilityEvent
* @see android.view.accessibility.AccessibilityManager
@@ -431,6 +431,16 @@ public class AccessibilityServiceInfo implements Parcelable {
private int mCapabilities;
/**
+ * Resource id of the summary of the accessibility service.
+ */
+ private int mSummaryResId;
+
+ /**
+ * Non-localized summary of the accessibility service.
+ */
+ private String mNonLocalizedSummary;
+
+ /**
* Resource id of the description of the accessibility service.
*/
private int mDescriptionResId;
@@ -544,6 +554,15 @@ public class AccessibilityServiceInfo implements Parcelable {
mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
}
}
+ peekedValue = asAttributes.peekValue(
+ com.android.internal.R.styleable.AccessibilityService_summary);
+ if (peekedValue != null) {
+ mSummaryResId = peekedValue.resourceId;
+ CharSequence nonLocalizedSummary = peekedValue.coerceToString();
+ if (nonLocalizedSummary != null) {
+ mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
+ }
+ }
asAttributes.recycle();
} catch (NameNotFoundException e) {
throw new XmlPullParserException( "Unable to create context for: "
@@ -669,6 +688,27 @@ public class AccessibilityServiceInfo implements Parcelable {
}
/**
+ * The localized summary of the accessibility service.
+ * <p>
+ * <strong>Statically set from
+ * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+ * </p>
+ * @return The localized summary.
+ */
+ public String loadSummary(PackageManager packageManager) {
+ if (mSummaryResId == 0) {
+ return mNonLocalizedSummary;
+ }
+ ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
+ CharSequence summary = packageManager.getText(serviceInfo.packageName,
+ mSummaryResId, serviceInfo.applicationInfo);
+ if (summary != null) {
+ return summary.toString().trim();
+ }
+ return null;
+ }
+
+ /**
* Gets the non-localized description of the accessibility service.
* <p>
* <strong>Statically set from
@@ -726,6 +766,8 @@ public class AccessibilityServiceInfo implements Parcelable {
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeInt(mCapabilities);
+ parcel.writeInt(mSummaryResId);
+ parcel.writeString(mNonLocalizedSummary);
parcel.writeInt(mDescriptionResId);
parcel.writeString(mNonLocalizedDescription);
}
@@ -740,6 +782,8 @@ public class AccessibilityServiceInfo implements Parcelable {
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mCapabilities = parcel.readInt();
+ mSummaryResId = parcel.readInt();
+ mNonLocalizedSummary = parcel.readString();
mDescriptionResId = parcel.readInt();
mNonLocalizedDescription = parcel.readString();
}
@@ -790,6 +834,8 @@ public class AccessibilityServiceInfo implements Parcelable {
stringBuilder.append(", ");
stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
stringBuilder.append(", ");
+ stringBuilder.append("summary: ").append(mNonLocalizedSummary);
+ stringBuilder.append(", ");
appendCapabilities(stringBuilder, mCapabilities);
return stringBuilder.toString();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e0dc10daf64d..d6306e001516 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1465,7 +1465,7 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SHOW_KEYBOARD_SHORTCUTS =
- "android.intent.action.SHOW_KEYBOARD_SHORTCUTS";
+ "com.android.intent.action.SHOW_KEYBOARD_SHORTCUTS";
/**
* Activity Action: Dismiss the Keyboard Shortcuts Helper screen.
@@ -1475,7 +1475,7 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DISMISS_KEYBOARD_SHORTCUTS =
- "android.intent.action.DISMISS_KEYBOARD_SHORTCUTS";
+ "com.android.intent.action.DISMISS_KEYBOARD_SHORTCUTS";
/**
* Activity Action: Show settings for managing network data usage of a
@@ -3124,7 +3124,7 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
public static final String ACTION_SHOW_BRIGHTNESS_DIALOG =
- "android.intent.action.SHOW_BRIGHTNESS_DIALOG";
+ "com.android.intent.action.SHOW_BRIGHTNESS_DIALOG";
/**
* Broadcast Action: A global button was pressed. Includes a single
diff --git a/core/java/android/content/pm/SELinuxUtil.java b/core/java/android/content/pm/SELinuxUtil.java
index 55b5e297e18f..025c0fe30877 100644
--- a/core/java/android/content/pm/SELinuxUtil.java
+++ b/core/java/android/content/pm/SELinuxUtil.java
@@ -32,11 +32,10 @@ public final class SELinuxUtil {
/** @hide */
public static String assignSeinfoUser(PackageUserState userState) {
- String seInfo = "";
- if (userState.instantApp)
- seInfo += INSTANT_APP_STR;
- seInfo += COMPLETE_STR;
- return seInfo;
+ if (userState.instantApp) {
+ return INSTANT_APP_STR + COMPLETE_STR;
+ }
+ return COMPLETE_STR;
}
}
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index 3f8f90ebf054..50fc3443f5a6 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -67,13 +67,14 @@ public class FontResourcesParser {
AttributeSet attrs = Xml.asAttributeSet(parser);
TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamily);
String authority = array.getString(R.styleable.FontFamily_fontProviderAuthority);
+ String providerPackage = array.getString(R.styleable.FontFamily_fontProviderPackage);
String query = array.getString(R.styleable.FontFamily_fontProviderQuery);
array.recycle();
- if (authority != null && query != null) {
+ if (authority != null && providerPackage != null && query != null) {
while (parser.next() != XmlPullParser.END_TAG) {
skip(parser);
}
- return new FontConfig.Family(authority, query);
+ return new FontConfig.Family(authority, providerPackage, query);
}
List<FontConfig.Font> fonts = new ArrayList<>();
while (parser.next() != XmlPullParser.END_TAG) {
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 0ee25744488c..612b1356e306 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -60,26 +60,51 @@ public class LogMaker {
return this;
}
+ public LogMaker clearCategory() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY);
+ return this;
+ }
+
public LogMaker setType(int type) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE, type);
return this;
}
+ public LogMaker clearType() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE);
+ return this;
+ }
+
public LogMaker setSubtype(int subtype) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE, subtype);
return this;
}
+ public LogMaker clearSubtype() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE);
+ return this;
+ }
+
public LogMaker setTimestamp(long timestamp) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP, timestamp);
return this;
}
+ public LogMaker clearTimestamp() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP);
+ return this;
+ }
+
public LogMaker setPackageName(String packageName) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, packageName);
return this;
}
+ public LogMaker clearPackageName() {
+ entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME);
+ return this;
+ }
+
public LogMaker setCounterName(String name) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME, name);
return this;
diff --git a/core/java/android/metrics/MetricsReader.java b/core/java/android/metrics/MetricsReader.java
index 079c2c93c05b..dd8a74d1bfae 100644
--- a/core/java/android/metrics/MetricsReader.java
+++ b/core/java/android/metrics/MetricsReader.java
@@ -16,10 +16,15 @@
package android.metrics;
import android.annotation.SystemApi;
+import android.util.EventLog;
+import android.util.EventLog.Event;
+import android.util.Log;
-import com.android.internal.logging.legacy.LegacyConversionLogger;
-import com.android.internal.logging.legacy.EventLogCollector;
+import com.android.internal.logging.MetricsLogger;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.Queue;
/**
@@ -28,41 +33,87 @@ import java.util.Queue;
*/
@SystemApi
public class MetricsReader {
- private EventLogCollector mReader;
- private Queue<LogMaker> mEventQueue;
+ private Queue<LogMaker> mEventQueue = new LinkedList<>();
private long mLastEventMs;
private long mCheckpointMs;
+ private int[] LOGTAGS = { MetricsLogger.LOGTAG };
- /** Open a new session and start reading logs.
+ /**
+ * Read the available logs into a new session.
*
- * Starts reading from the oldest log not already read by this reader object.
- * On first invocation starts from the oldest available log ion the system.
+ * The session will contain events starting from the oldest available
+ * log on the system up to the most recent at the time of this call.
+ *
+ * A call to {@link #checkpoint()} will cause the session to contain
+ * only events that occured after that call.
+ *
+ * This call will not return until the system buffer overflows the
+ * specified timestamp. If the specified timestamp is 0, then the
+ * call will return immediately since any logs 1970 have already been
+ * overwritten (n.b. if the underlying system has the capability to
+ * store many decades of system logs, this call may fail in
+ * interesting ways.)
+ *
+ * @param horizonMs block until this timestamp is overwritten, 0 for non-blocking read.
*/
- public void read(long startMs) {
- EventLogCollector reader = EventLogCollector.getInstance();
- LegacyConversionLogger logger = new LegacyConversionLogger();
- mLastEventMs = reader.collect(logger, startMs);
- mEventQueue = logger.getEvents();
+ public void read(long horizonMs) {
+ ArrayList<Event> nativeEvents = new ArrayList<>();
+ try {
+ EventLog.readEventsOnWrapping(LOGTAGS, horizonMs, nativeEvents);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ mEventQueue.clear();
+ for (EventLog.Event event : nativeEvents) {
+ final long eventTimestampMs = event.getTimeNanos() / 1000000;
+ if (eventTimestampMs > mCheckpointMs) {
+ Object data = event.getData();
+ Object[] objects;
+ if (data instanceof Object[]) {
+ objects = (Object[]) data;
+ } else {
+ // wrap scalar objects
+ objects = new Object[1];
+ objects[0] = data;
+ }
+ mEventQueue.add(new LogMaker(objects)
+ .setTimestamp(eventTimestampMs));
+ mLastEventMs = eventTimestampMs;
+ }
+ }
}
+ /** Cause this session to only contain events that occur after this call. */
public void checkpoint() {
+ // read the log to find the most recent event.
read(0L);
+ // any queued event is now too old, so drop them.
+ mEventQueue.clear();
mCheckpointMs = mLastEventMs;
- mEventQueue = null;
}
+ /**
+ * Rewind the session to the beginning of time and read all available logs.
+ *
+ * A prior call to {@link #checkpoint()} will cause the reader to ignore
+ * any event with a timestamp before the time of that call.
+ *
+ * The underlying log buffer is live: between calls to {@link #reset()}, older
+ * events may be lost from the beginning of the session, and new events may
+ * appear at the end.
+ */
public void reset() {
- read(mCheckpointMs);
+ read(0l);
}
/* Does the current log session have another entry? */
public boolean hasNext() {
- return mEventQueue == null ? false : !mEventQueue.isEmpty();
+ return !mEventQueue.isEmpty();
}
- /* Next entry in the current log session. */
+ /* Return the next entry in the current log session. */
public LogMaker next() {
- return mEventQueue == null ? null : mEventQueue.remove();
+ return mEventQueue.poll();
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1259de602f29..14333f732d14 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1069,26 +1069,6 @@ public class ConnectivityManager {
}
/**
- * Request that this callback be invoked at ConnectivityService's earliest
- * convenience with the current satisfying network's LinkProperties.
- * If no such network exists no callback invocation is performed.
- *
- * The callback must have been registered with #requestNetwork() or
- * #registerDefaultNetworkCallback(); callbacks registered with
- * registerNetworkCallback() are not specific to any particular Network so
- * do not cause any updates.
- *
- * @hide
- */
- public void requestLinkProperties(NetworkCallback networkCallback) {
- try {
- mService.requestLinkProperties(networkCallback.networkRequest);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown.
* <p>This method requires the caller to hold the permission
@@ -1106,26 +1086,6 @@ public class ConnectivityManager {
}
/**
- * Request that this callback be invoked at ConnectivityService's earliest
- * convenience with the current satisfying network's NetworkCapabilities.
- * If no such network exists no callback invocation is performed.
- *
- * The callback must have been registered with #requestNetwork() or
- * #registerDefaultNetworkCallback(); callbacks registered with
- * registerNetworkCallback() are not specific to any particular Network so
- * do not cause any updates.
- *
- * @hide
- */
- public void requestNetworkCapabilities(NetworkCallback networkCallback) {
- try {
- mService.requestNetworkCapabilities(networkCallback.networkRequest);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Gets the URL that should be used for resolving whether a captive portal is present.
* 1. This URL should respond with a 204 response to a GET request to indicate no captive
* portal is present.
@@ -2676,10 +2636,12 @@ public class ConnectivityManager {
public void onLost(Network network) {}
/**
- * Called if no network is found in the given timeout time. If no timeout is given,
- * this will not be called. The associated {@link NetworkRequest} will have already
- * been removed and released, as if {@link #unregisterNetworkCallback} had been called.
- * @hide
+ * Called if no network is found in the timeout time specified in
+ * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} call. This callback is not
+ * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
+ * without timeout. When this callback is invoked the associated
+ * {@link NetworkRequest} will have already been removed and released, as if
+ * {@link #unregisterNetworkCallback(NetworkCallback)} had been called.
*/
public void onUnavailable() {}
@@ -2962,7 +2924,9 @@ public class ConnectivityManager {
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
+ * version of the method which takes a timeout is
+ * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
@@ -2995,7 +2959,9 @@ public class ConnectivityManager {
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
+ * version of the method which takes a timeout is
+ * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
@@ -3029,13 +2995,25 @@ public class ConnectivityManager {
}
/**
+ * Note: this is a deprecated version of
+ * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} - please transition code to use
+ * the unhidden version of the function.
+ * TODO: replace all callers with the new version of the API
+ *
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
* by a timeout.
*
- * This function behaves identically to the non-timedout version, but if a suitable
- * network is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#onUnavailable()} callback is called. The request must
- * still be released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
+ * This function behaves identically to the non-timed-out version
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network
+ * is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be
+ * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
+ * not have to be released if timed-out (it is automatically released). Unregistering a
+ * request that timed out is not an error.
+ *
+ * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
+ * timeout) - the {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
+ * for that purpose. Calling this method will attempt to bring up the requested network.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3043,15 +3021,56 @@ public class ConnectivityManager {
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * The callback is invoked on the default internal Handler.
+ * @param networkCallback The callbacks to be utilized for this request. Note
+ * the callbacks must not be shared - they uniquely specify
+ * this request.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable()} is called.
+ * before {@link NetworkCallback#onUnavailable()} is called. The timeout must
+ * be a positive value (i.e. >0).
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs) {
+ if (timeoutMs <= 0) {
+ throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
+ }
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * by a timeout.
+ *
+ * This function behaves identically to the non-timed-out version
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network
+ * is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be
+ * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
+ * not have to be released if timed-out (it is automatically released). Unregistering a
+ * request that timed out is not an error.
+ *
+ * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
+ * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
+ * for that purpose. Calling this method will attempt to bring up the requested network.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#onUnavailable()} is called. The timeout must
+ * be a positive value (i.e. >0).
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ */
+ public void requestNetwork(NetworkRequest request, int timeoutMs,
+ NetworkCallback networkCallback) {
+ if (timeoutMs <= 0) {
+ throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
+ }
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
}
@@ -3063,8 +3082,14 @@ public class ConnectivityManager {
*
* This function behaves identically to the non-timedout version, but if a suitable
* network is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#onUnavailable} callback is called. The request must
- * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
+ * {@link NetworkCallback#onUnavailable} callback is called. The request can still be
+ * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
+ * not have to be released if timed-out (it is automatically released). Unregistering a
+ * request that timed out is not an error.
+ *
+ * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
+ * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
+ * for that purpose. Calling this method will attempt to bring up the requested network.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3072,16 +3097,19 @@ public class ConnectivityManager {
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable} is called.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
*
* @hide
*/
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs, Handler handler) {
+ public void requestNetwork(NetworkRequest request, int timeoutMs,
+ NetworkCallback networkCallback, Handler handler) {
+ if (timeoutMs <= 0) {
+ throw new IllegalArgumentException("Non-positive timeoutMs");
+ }
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
CallbackHandler cbHandler = new CallbackHandler(handler);
requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 117fa0b476f4..425e49407827 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -156,8 +156,6 @@ interface IConnectivityManager
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation);
- void requestLinkProperties(in NetworkRequest networkRequest);
- void requestNetworkCapabilities(in NetworkRequest networkRequest);
void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index bd3231464ccf..2c9ce3f99285 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -839,7 +839,7 @@ public final class NdefRecord implements Parcelable {
if (cf && !inChunk) {
// first chunk
- if (typeLength == 0) {
+ if (typeLength == 0 && tnf != NdefRecord.TNF_UNKNOWN) {
throw new FormatException("expected non-zero type length in first chunk");
}
chunks.clear();
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 90e710f12c08..96dd76b8fe72 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -19,9 +19,12 @@ import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
+import android.content.pm.Signature;
import android.database.Cursor;
+import android.graphics.Typeface;
import android.graphics.fonts.FontRequest;
import android.graphics.fonts.FontResult;
import android.net.Uri;
@@ -34,9 +37,13 @@ import android.os.ResultReceiver;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* Utility class to deal with Font ContentProviders.
@@ -107,6 +114,13 @@ public class FontsContract {
mPackageManager = mContext.getPackageManager();
}
+ /** @hide */
+ @VisibleForTesting
+ public FontsContract(Context context, PackageManager packageManager) {
+ mContext = context;
+ mPackageManager = packageManager;
+ }
+
// We use a background thread to post the content resolving work for all requests on. This
// thread should be quit/stopped after all requests are done.
private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() {
@@ -133,31 +147,79 @@ public class FontsContract {
mHandler = new Handler(mThread.getLooper());
}
mHandler.post(() -> {
- String providerAuthority = request.getProviderAuthority();
- // TODO: Implement cert checking for non-system apps
- ProviderInfo providerInfo = mPackageManager.resolveContentProvider(
- providerAuthority, PackageManager.MATCH_SYSTEM_ONLY);
+ ProviderInfo providerInfo = getProvider(request);
if (providerInfo == null) {
receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
return;
}
- Bundle result = getFontFromProvider(request, receiver, providerInfo);
- if (result == null) {
- receiver.send(RESULT_CODE_FONT_NOT_FOUND, null);
- return;
- }
- receiver.send(RESULT_CODE_OK, result);
+ getFontFromProvider(request, receiver, providerInfo.authority);
});
mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
}
}
- private Bundle getFontFromProvider(FontRequest request, ResultReceiver receiver,
- ProviderInfo providerInfo) {
+ /** @hide */
+ @VisibleForTesting
+ public ProviderInfo getProvider(FontRequest request) {
+ String providerAuthority = request.getProviderAuthority();
+ ProviderInfo info = mPackageManager.resolveContentProvider(providerAuthority, 0);
+ if (info == null) {
+ Log.e(TAG, "Can't find content provider " + providerAuthority);
+ return null;
+ }
+
+ if (!info.packageName.equals(request.getProviderPackage())) {
+ Log.e(TAG, "Found content provider " + providerAuthority + ", but package was not "
+ + request.getProviderPackage());
+ return null;
+ }
+ // Trust system apps without signature checks
+ if (info.applicationInfo.isSystemApp()) {
+ return info;
+ }
+
+ Set<byte[]> signatures;
+ try {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(info.packageName,
+ PackageManager.GET_SIGNATURES);
+ signatures = convertToSet(packageInfo.signatures);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Can't find content provider " + providerAuthority, e);
+ return null;
+ }
+ List<List<byte[]>> requestCertificatesList = request.getCertificates();
+ for (int i = 0; i < requestCertificatesList.size(); ++i) {
+ final Set<byte[]> requestCertificates = convertToSet(requestCertificatesList.get(i));
+ if (signatures.equals(requestCertificates)) {
+ return info;
+ }
+ }
+ Log.e(TAG, "Certificates don't match for given provider " + providerAuthority);
+ return null;
+ }
+
+ private Set<byte[]> convertToSet(Signature[] signatures) {
+ Set<byte[]> shas = new HashSet<>();
+ for (int i = 0; i < signatures.length; ++i) {
+ shas.add(signatures[i].toByteArray());
+ }
+ return shas;
+ }
+
+ private Set<byte[]> convertToSet(List<byte[]> certs) {
+ Set<byte[]> shas = new HashSet<>();
+ shas.addAll(certs);
+ return shas;
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public void getFontFromProvider(FontRequest request, ResultReceiver receiver,
+ String authority) {
ArrayList<FontResult> result = null;
Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(providerInfo.authority)
+ .authority(authority)
.build();
try (Cursor cursor = mContext.getContentResolver().query(uri, new String[] { Columns._ID,
Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.STYLE },
@@ -176,13 +238,16 @@ public class FontsContract {
try {
ParcelFileDescriptor pfd =
mContext.getContentResolver().openFileDescriptor(fileUri, "r");
- final int ttcIndex = cursor.getInt(ttcIndexColumnIndex);
- final String variationSettings = cursor.getString(vsColumnIndex);
- final int style = cursor.getInt(styleColumnIndex);
+ final int ttcIndex = ttcIndexColumnIndex != -1
+ ? cursor.getInt(ttcIndexColumnIndex) : 0;
+ final String variationSettings = vsColumnIndex != -1
+ ? cursor.getString(vsColumnIndex) : null;
+ final int style = styleColumnIndex != -1
+ ? cursor.getInt(styleColumnIndex) : Typeface.NORMAL;
result.add(new FontResult(pfd, ttcIndex, variationSettings, style));
} catch (FileNotFoundException e) {
Log.e(TAG, "FileNotFoundException raised when interacting with content "
- + "provider " + providerInfo.authority, e);
+ + "provider " + authority, e);
}
}
}
@@ -190,8 +255,9 @@ public class FontsContract {
if (result != null && !result.isEmpty()) {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
- return bundle;
+ receiver.send(RESULT_CODE_OK, bundle);
+ return;
}
- return null;
+ receiver.send(RESULT_CODE_FONT_NOT_FOUND, null);
}
}
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 82e44dc86f89..1087851c853f 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -403,6 +403,7 @@ public final class FontConfig implements Parcelable {
private final String mLanguage;
private final String mVariant;
private final String mProviderAuthority;
+ private final String mProviderPackage;
private final String mQuery;
public Family(String name, List<Font> fonts, String language, String variant) {
@@ -411,18 +412,20 @@ public final class FontConfig implements Parcelable {
mLanguage = language;
mVariant = variant;
mProviderAuthority = null;
+ mProviderPackage = null;
mQuery = null;
}
/**
* @hide
*/
- public Family(String providerAuthority, String query) {
+ public Family(String providerAuthority, String providerPackage, String query) {
mName = null;
mFonts = null;
mLanguage = null;
mVariant = null;
mProviderAuthority = providerAuthority;
+ mProviderPackage = providerPackage;
mQuery = query;
}
@@ -435,6 +438,7 @@ public final class FontConfig implements Parcelable {
mFonts.add(new Font(origin.mFonts.get(i)));
}
mProviderAuthority = origin.mProviderAuthority;
+ mProviderPackage = origin.mProviderPackage;
mQuery = origin.mQuery;
}
@@ -476,6 +480,13 @@ public final class FontConfig implements Parcelable {
/**
* @hide
*/
+ public String getProviderPackage() {
+ return mProviderPackage;
+ }
+
+ /**
+ * @hide
+ */
public String getQuery() {
return mQuery;
}
@@ -498,6 +509,11 @@ public final class FontConfig implements Parcelable {
mProviderAuthority = null;
}
if (in.readInt() == 1) {
+ mProviderPackage = in.readString();
+ } else {
+ mProviderPackage = null;
+ }
+ if (in.readInt() == 1) {
mQuery = in.readString();
} else {
mQuery = null;
@@ -517,6 +533,10 @@ public final class FontConfig implements Parcelable {
if (mProviderAuthority != null) {
out.writeString(mProviderAuthority);
}
+ out.writeInt(mProviderPackage == null ? 0 : 1);
+ if (mProviderPackage != null) {
+ out.writeString(mProviderPackage);
+ }
out.writeInt(mQuery == null ? 0 : 1);
if (mQuery != null) {
out.writeString(mQuery);
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 80ec03e70cb7..c2508a6c92ef 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -42,13 +42,24 @@ public class Hyphenator {
private static String TAG = "Hyphenator";
+ // TODO: Confirm that these are the best values. Various sources suggest (1, 1), but
+ // that appears too small.
+ private static final int INDIC_MIN_PREFIX = 2;
+ private static final int INDIC_MIN_SUFFIX = 2;
+
private final static Object sLock = new Object();
@GuardedBy("sLock")
final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
+ // Reasonable enough values for cases where we have no hyphenation patterns but may be able to
+ // do some automatic hyphenation based on characters. These values would be used very rarely.
+ private static final int DEFAULT_MIN_PREFIX = 2;
+ private static final int DEFAULT_MIN_SUFFIX = 2;
final static Hyphenator sEmptyHyphenator =
- new Hyphenator(StaticLayout.nLoadHyphenator(null, 0), null);
+ new Hyphenator(StaticLayout.nLoadHyphenator(
+ null, 0, DEFAULT_MIN_PREFIX, DEFAULT_MIN_SUFFIX),
+ null);
final private long mNativePtr;
@@ -111,15 +122,26 @@ public class Hyphenator {
return sEmptyHyphenator;
}
- private static Hyphenator loadHyphenator(String languageTag) {
- String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb";
+ private static class HyphenationData {
+ final String mLanguageTag;
+ final int mMinPrefix, mMinSuffix;
+ HyphenationData(String languageTag, int minPrefix, int minSuffix) {
+ this.mLanguageTag = languageTag;
+ this.mMinPrefix = minPrefix;
+ this.mMinSuffix = minSuffix;
+ }
+ }
+
+ private static Hyphenator loadHyphenator(HyphenationData data) {
+ String patternFilename = "hyph-" + data.mLanguageTag.toLowerCase(Locale.US) + ".hyb";
File patternFile = new File(getSystemHyphenatorLocation(), patternFilename);
try {
RandomAccessFile f = new RandomAccessFile(patternFile, "r");
try {
FileChannel fc = f.getChannel();
MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
- long nativePtr = StaticLayout.nLoadHyphenator(buf, 0);
+ long nativePtr = StaticLayout.nLoadHyphenator(
+ buf, 0, data.mMinPrefix, data.mMinSuffix);
return new Hyphenator(nativePtr, buf);
} finally {
f.close();
@@ -176,6 +198,46 @@ public class Hyphenator {
{"wal", "und-Ethi"}, // Wolaytta
};
+ private static final HyphenationData[] AVAILABLE_LANGUAGES = {
+ new HyphenationData("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Assamese
+ new HyphenationData("bg", 2, 2), // Bulgarian
+ new HyphenationData("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Bengali
+ new HyphenationData("cu", 1, 2), // Church Slavonic
+ new HyphenationData("cy", 2, 3), // Welsh
+ new HyphenationData("da", 2, 2), // Danish
+ new HyphenationData("de-1901", 2, 2), // German 1901 orthography
+ new HyphenationData("de-1996", 2, 2), // German 1996 orthography
+ new HyphenationData("de-CH-1901", 2, 2), // Swiss High German 1901 orthography
+ new HyphenationData("en-GB", 2, 3), // British English
+ new HyphenationData("en-US", 2, 3), // American English
+ new HyphenationData("es", 2, 2), // Spanish
+ new HyphenationData("et", 2, 3), // Estonian
+ new HyphenationData("eu", 2, 2), // Basque
+ new HyphenationData("fr", 2, 3), // French
+ new HyphenationData("ga", 2, 3), // Irish
+ new HyphenationData("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Gujarati
+ new HyphenationData("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Hindi
+ new HyphenationData("hr", 2, 2), // Croatian
+ new HyphenationData("hu", 2, 2), // Hungarian
+ // texhyphen sources say Armenian may be (1, 2), but that it needs confirmation.
+ // Going with a more conservative value of (2, 2) for now.
+ new HyphenationData("hy", 2, 2), // Armenian
+ new HyphenationData("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Kannada
+ new HyphenationData("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Malayalam
+ new HyphenationData("mn-Cyrl", 2, 2), // Mongolian in Cyrillic script
+ new HyphenationData("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Marathi
+ new HyphenationData("nb", 2, 2), // Norwegian Bokmål
+ new HyphenationData("nn", 2, 2), // Norwegian Nynorsk
+ new HyphenationData("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Oriya
+ new HyphenationData("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Punjabi
+ new HyphenationData("pt", 2, 3), // Portuguese
+ new HyphenationData("sl", 2, 2), // Slovenian
+ new HyphenationData("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Tamil
+ new HyphenationData("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Telugu
+ new HyphenationData("tk", 2, 2), // Turkmen
+ new HyphenationData("und-Ethi", 1, 1), // Any language in Ethiopic script
+ };
+
/**
* Load hyphenation patterns at initialization time. We want to have patterns
* for all locales loaded and ready to use so we don't have to do any file IO
@@ -186,46 +248,11 @@ public class Hyphenator {
public static void init() {
sMap.put(null, null);
- // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
- String[] availableLanguages = {
- "as",
- "bg",
- "bn",
- "cu",
- "cy",
- "da",
- "de-1901", "de-1996", "de-CH-1901",
- "en-GB", "en-US",
- "es",
- "et",
- "eu",
- "fr",
- "ga",
- "gu",
- "hi",
- "hr",
- "hu",
- "hy",
- "kn",
- "ml",
- "mn-Cyrl",
- "mr",
- "nb",
- "nn",
- "or",
- "pa",
- "pt",
- "sl",
- "ta",
- "te",
- "tk",
- "und-Ethi",
- };
- for (int i = 0; i < availableLanguages.length; i++) {
- String languageTag = availableLanguages[i];
- Hyphenator h = loadHyphenator(languageTag);
+ for (int i = 0; i < AVAILABLE_LANGUAGES.length; i++) {
+ HyphenationData data = AVAILABLE_LANGUAGES[i];
+ Hyphenator h = loadHyphenator(data);
if (h != null) {
- sMap.put(Locale.forLanguageTag(languageTag), h);
+ sMap.put(Locale.forLanguageTag(data.mLanguageTag), h);
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index cb5b073318d8..94c463c8e651 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1290,7 +1290,8 @@ public class StaticLayout extends Layout {
private static native void nFreeBuilder(long nativePtr);
private static native void nFinishBuilder(long nativePtr);
- /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset);
+ /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset,
+ int minPrefix, int minSuffix);
private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 910a6b191a01..ca3985449d92 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -243,12 +243,12 @@ public class Patterns {
public static final String GOOD_IRI_CHAR =
"a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
- public static final Pattern IP_ADDRESS
- = Pattern.compile(
+ private static final String IP_ADDRESS_STRING =
"((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
- + "|[1-9][0-9]|[0-9]))");
+ + "|[1-9][0-9]|[0-9]))";
+ public static final Pattern IP_ADDRESS = Pattern.compile(IP_ADDRESS_STRING);
/**
* Valid UCS characters defined in RFC 3987. Excludes space characters.
@@ -298,8 +298,8 @@ public class Patterns {
private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD;
- public static final Pattern DOMAIN_NAME
- = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
+ private static final String DOMAIN_NAME_STR = "(" + HOST_NAME + "|" + IP_ADDRESS_STRING + ")";
+ public static final Pattern DOMAIN_NAME = Pattern.compile(DOMAIN_NAME_STR);
private static final String PROTOCOL = "(?i:http|https|rtsp)://";
@@ -323,7 +323,7 @@ public class Patterns {
public static final Pattern WEB_URL = Pattern.compile("("
+ "("
+ "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?"
- + "(?:" + DOMAIN_NAME + ")"
+ + "(?:" + DOMAIN_NAME_STR + ")"
+ "(?:" + PORT_NUMBER + ")?"
+ ")"
+ "(" + PATH_AND_QUERY + ")?"
@@ -346,14 +346,14 @@ public class Patterns {
* Regular expression that matches domain names using either {@link #STRICT_HOST_NAME} or
* {@link #IP_ADDRESS}
*/
- private static final Pattern STRICT_DOMAIN_NAME
- = Pattern.compile("(?:" + STRICT_HOST_NAME + "|" + IP_ADDRESS + ")");
+ private static final String STRICT_DOMAIN_NAME = "(?:" + STRICT_HOST_NAME + "|"
+ + IP_ADDRESS_STRING + ")";
/**
* Regular expression that matches domain names without a TLD
*/
private static final String RELAXED_DOMAIN_NAME =
- "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS + ")";
+ "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS_STRING + ")";
/**
* Regular expression to match strings that do not start with a supported protocol. The TLDs
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index c7340bfa329e..782f3499fb79 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -38,9 +38,11 @@ oneway interface IPinnedStackListener {
* to be changed (ie. after configuration change, aspect ratio change, etc). It then provides
* the components that allow the listener to calculate the movement bounds itself. The
* {@param normalBounds} are also the default bounds that the PiP would be entered in its
- * current state with the aspect ratio applied.
+ * current state with the aspect ratio applied. The {@param animatingBounds} are provided
+ * to indicate the current target bounds of the pinned stack (the final bounds if animating,
+ * the current bounds if not), which may be helpful in calculating dependent animation bounds.
*/
- void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds,
+ void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds,
boolean fromImeAdjustement);
/**
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 16d46666732d..fe9197867484 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -23,9 +23,7 @@ import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -67,33 +65,6 @@ public class NotificationHeaderView extends ViewGroup {
}
}
};
- final AccessibilityDelegate mExpandDelegate = new AccessibilityDelegate() {
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (super.performAccessibilityAction(host, action, args)) {
- return true;
- }
- if (action == AccessibilityNodeInfo.ACTION_COLLAPSE
- || action == AccessibilityNodeInfo.ACTION_EXPAND) {
- mExpandClickListener.onClick(mExpandButton);
- return true;
- }
- return false;
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- // Avoid that the button description is also spoken
- info.setClassName(getClass().getName());
- if (mExpanded) {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
- } else {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
- }
- }
- };
private boolean mAcceptAllTouches;
public NotificationHeaderView(Context context) {
@@ -124,9 +95,6 @@ public class NotificationHeaderView extends ViewGroup {
mAppName = findViewById(com.android.internal.R.id.app_name_text);
mHeaderText = findViewById(com.android.internal.R.id.header_text);
mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
- if (mExpandButton != null) {
- mExpandButton.setAccessibilityDelegate(mExpandDelegate);
- }
mIcon = (CachingIconView) findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
}
@@ -295,13 +263,19 @@ public class NotificationHeaderView extends ViewGroup {
private void updateExpandButton() {
int drawableId;
+ int contentDescriptionId;
if (mExpanded) {
drawableId = com.android.internal.R.drawable.ic_collapse_notification;
+ contentDescriptionId
+ = com.android.internal.R.string.expand_button_content_description_expanded;
} else {
drawableId = com.android.internal.R.drawable.ic_expand_notification;
+ contentDescriptionId
+ = com.android.internal.R.string.expand_button_content_description_collapsed;
}
mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
mExpandButton.setColorFilter(mOriginalNotificationColor);
+ mExpandButton.setContentDescription(mContext.getText(contentDescriptionId));
}
public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
@@ -391,7 +365,7 @@ public class NotificationHeaderView extends ViewGroup {
break;
case MotionEvent.ACTION_UP:
if (mTrackGesture) {
- mExpandClickListener.onClick(NotificationHeaderView.this);
+ mExpandButton.performClick();
}
break;
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 97a36fd71c0f..536d7e088021 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -201,7 +201,7 @@ final class TextClassifierImpl implements TextClassifier {
Preconditions.checkArgument(text != null);
Preconditions.checkArgument(startIndex >= 0);
Preconditions.checkArgument(endIndex <= text.length());
- Preconditions.checkArgument(endIndex >= startIndex);
+ Preconditions.checkArgument(endIndex > startIndex);
}
/**
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 679053299666..b75193536f32 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -60,14 +60,14 @@ final class SelectionActionModeHelper {
mEditor = Preconditions.checkNotNull(editor);
final TextView textView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
- textView.getTextClassifier(), textView.getText(),
- textView.getSelectionStart(), textView.getSelectionEnd());
+ textView.getTextClassifier(), textView.getText(), 0, 1);
}
public void startActionModeAsync() {
cancelAsyncTask();
- if (isNoOpTextClassifier()) {
+ if (isNoOpTextClassifier() || !hasSelection()) {
// No need to make an async call for a no-op TextClassifier.
+ // Do not call the TextClassifier if there is no selection.
startActionMode(null);
} else {
resetTextClassificationHelper();
@@ -84,8 +84,9 @@ final class SelectionActionModeHelper {
public void invalidateActionModeAsync() {
cancelAsyncTask();
- if (isNoOpTextClassifier()) {
+ if (isNoOpTextClassifier() || !hasSelection()) {
// No need to make an async call for a no-op TextClassifier.
+ // Do not call the TextClassifier if there is no selection.
invalidateActionMode(null);
} else {
resetTextClassificationHelper();
@@ -126,6 +127,11 @@ final class SelectionActionModeHelper {
return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
}
+ private boolean hasSelection() {
+ final TextView textView = mEditor.getTextView();
+ return textView.getSelectionEnd() > textView.getSelectionStart();
+ }
+
private void startActionMode(@Nullable SelectionResult result) {
final TextView textView = mEditor.getTextView();
final CharSequence text = textView.getText();
@@ -311,6 +317,7 @@ final class SelectionActionModeHelper {
CharSequence text, int selectionStart, int selectionEnd) {
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
+ Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
}
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index cf1bf62cdeb2..bab7cb352563 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -19,6 +19,7 @@ package com.android.internal.hardware;
import com.android.internal.R;
import android.content.Context;
+import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
@@ -33,7 +34,8 @@ public class AmbientDisplayConfiguration {
public boolean enabled(int user) {
return pulseOnNotificationEnabled(user)
|| pulseOnPickupEnabled(user)
- || pulseOnDoubleTapEnabled(user);
+ || pulseOnDoubleTapEnabled(user)
+ || alwaysOnEnabled(user);
}
public boolean available() {
@@ -72,6 +74,16 @@ public class AmbientDisplayConfiguration {
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
+ public boolean alwaysOnEnabled(int user) {
+ return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user)
+ && alwaysOnAvailable();
+ }
+
+ public boolean alwaysOnAvailable() {
+ // TODO: introduce config_dozeAlwaysOnAvailable. For now just debuggable builds.
+ return Build.IS_DEBUGGABLE && ambientDisplayAvailable();
+ }
+
public String ambientDisplayComponent() {
return mContext.getResources().getString(R.string.config_dozeComponent);
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index c8bf302e46d5..949e7ac50a7b 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -29,8 +29,10 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
*/
public class MetricsLogger {
// define metric categories in frameworks/base/proto/src/metrics_constants.proto.
+ // mirror changes in native version at system/core/libmetricslogger/metrics_logger.cpp
public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
+ public static final int LOGTAG = EventLogTags.SYSUI_MULTI_ACTION;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
@@ -125,6 +127,7 @@ public class MetricsLogger {
/** Increment the bucket with the integer label on the histogram with the given name. */
public static void histogram(Context context, String name, int bucket) {
+ // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
EventLogTags.writeSysuiHistogram(name, bucket);
EventLogTags.writeSysuiMultiAction(
new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
diff --git a/core/java/com/android/internal/logging/legacy/EventLogCollector.java b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
deleted file mode 100644
index 598f0d51c1b9..000000000000
--- a/core/java/com/android/internal/logging/legacy/EventLogCollector.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.util.ArrayMap;
-import android.util.EventLog;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Scan the event log for interaction metrics events.
- * @hide
- */
-public class EventLogCollector {
- private static final String TAG = "EventLogCollector";
-
- // TODO replace this with GoogleLogTags.TRON_HEARTBEAT
- @VisibleForTesting
- static final int TRON_HEARTBEAT = 208000;
-
- private static EventLogCollector sInstance;
-
- private final ArrayMap<Integer, TagParser> mTagParsers;
- private int[] mInterestingTags;
-
- private LogReader mLogReader;
-
- private EventLogCollector() {
- mTagParsers = new ArrayMap<>();
- addParser(new PowerScreenStateParser());
- addParser(new SysuiMultiActionParser());
-
- mLogReader = new LogReader();
- }
-
- public static EventLogCollector getInstance() {
- if (sInstance == null) {
- sInstance = new EventLogCollector();
- }
- return sInstance;
- }
-
- @VisibleForTesting
- public void setLogReader(LogReader logReader) {
- mLogReader = logReader;
- }
-
- private int[] getInterestingTags() {
- if (mInterestingTags == null) {
- mInterestingTags = new int[mTagParsers.size()];
- for (int i = 0; i < mTagParsers.size(); i++) {
- mInterestingTags[i] = mTagParsers.valueAt(i).getTag();
- }
- }
- return mInterestingTags;
- }
-
- // I would customize ArrayMap to add put(TagParser), but ArrayMap is final.
- @VisibleForTesting
- void addParser(TagParser parser) {
- mTagParsers.put(parser.getTag(), parser);
- mInterestingTags = null;
- }
-
- public void collect(LegacyConversionLogger logger) {
- collect(logger, 0L);
- }
-
- public long collect(TronLogger logger, long lastSeenEventMs) {
- long lastEventMs = 0L;
- final boolean debug = Util.debug();
-
- if (debug) {
- Log.d(TAG, "Eventlog Collection");
- }
- ArrayList<Event> events = new ArrayList<>();
- try {
- mLogReader.readEvents(getInterestingTags(), events);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (debug) {
- Log.d(TAG, "read this many events: " + events.size());
- }
-
- for (Event event : events) {
- final long millis = event.getTimeNanos() / 1000000;
- if (millis > lastSeenEventMs) {
- final int tag = event.getTag();
- TagParser parser = mTagParsers.get(tag);
- if (parser == null) {
- if (debug) {
- Log.d(TAG, "unknown tag: " + tag);
- }
- continue;
- }
- if (debug) {
- Log.d(TAG, "parsing tag: " + tag);
- }
- parser.parseEvent(logger, event);
- lastEventMs = Math.max(lastEventMs, millis);
- } else {
- if (debug) {
- Log.d(TAG, "old event: " + millis + " < " + lastSeenEventMs);
- }
- }
- }
- return lastEventMs;
- }
-
- @VisibleForTesting
- static class Event {
- long mTimeNanos;
- int mTag;
- Object mData;
-
- Event(long timeNanos, int tag, Object data) {
- super();
- mTimeNanos = timeNanos;
- mTag = tag;
- mData = data;
- }
-
- Event(EventLog.Event event) {
- mTimeNanos = event.getTimeNanos();
- mTag = event.getTag();
- mData = event.getData();
- }
-
- public long getTimeNanos() {
- return mTimeNanos;
- }
-
- public int getTag() {
- return mTag;
- }
-
- public Object getData() {
- return mData;
- }
- }
-
- @VisibleForTesting
- static class LogReader {
- public void readEvents(int[] tags, Collection<Event> events) throws IOException {
- // Testing in Android: the Static Final Class Strikes Back!
- ArrayList<EventLog.Event> nativeEvents = new ArrayList<>();
- EventLog.readEventsOnWrapping(tags, 0L, nativeEvents);
- for (EventLog.Event nativeEvent : nativeEvents) {
- Event event = new Event(nativeEvent);
- events.add(event);
- }
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
deleted file mode 100644
index 1209e4d8dc8c..000000000000
--- a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Queue;
-
-/** @hide */
-public class LegacyConversionLogger implements TronLogger {
- private final Queue<LogMaker> mQueue;
- private HashMap<String, Boolean> mConfig;
-
- public LegacyConversionLogger() {
- mQueue = new LinkedList<>();
- }
-
- public Queue<LogMaker> getEvents() {
- return mQueue;
- }
-
- @Override
- public void increment(String counterName) {
- LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
- .setCounterName(counterName)
- .setCounterValue(1);
- mQueue.add(b);
- }
-
- @Override
- public void incrementBy(String counterName, int value) {
- LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
- .setCounterName(counterName)
- .setCounterValue(value);
- mQueue.add(b);
- }
-
- @Override
- public void incrementIntHistogram(String counterName, int bucket) {
- LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
- .setCounterName(counterName)
- .setCounterBucket(bucket)
- .setCounterValue(1);
- mQueue.add(b);
- }
-
- @Override
- public void incrementLongHistogram(String counterName, long bucket) {
- LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
- .setCounterName(counterName)
- .setCounterBucket(bucket)
- .setCounterValue(1);
- mQueue.add(b);
- }
-
- @Override
- public LogMaker obtain() {
- return new LogMaker(MetricsEvent.VIEW_UNKNOWN);
- }
-
- @Override
- public void dispose(LogMaker proto) {
- }
-
- @Override
- public void addEvent(LogMaker proto) {
- mQueue.add(proto);
- }
-
- @Override
- public boolean getConfig(String configName) {
- if (mConfig != null && mConfig.containsKey(configName)) {
- return mConfig.get(configName);
- }
- return false;
- }
-
- @Override
- public void setConfig(String configName, boolean newValue) {
- if (mConfig == null) {
- mConfig = new HashMap<>();
- }
- mConfig.put(configName, newValue);
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java b/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java
deleted file mode 100644
index e9baf9baf8da..000000000000
--- a/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Parse the Android lockscreen gesture logs.
- * @hide
- */
-public class PowerScreenStateParser extends TagParser {
- private static final String TAG = "PowerScreenStateParser";
- private static final int EVENTLOG_TAG = 2728;
-
- // source of truth is android.view.WindowManagerPolicy, why:
- // 0: on
- // 1: OFF_BECAUSE_OF_ADMIN
- // 2: OFF_BECAUSE_OF_USER
- // 3: OFF_BECAUSE_OF_TIMEOUT
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- if (operands.length >= 2) {
- try {
- // (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
- boolean state = (((Integer) operands[0]).intValue()) == 1;
- int why = ((Integer) operands[1]).intValue();
-
- LogMaker proto = logger.obtain();
- proto.setCategory(MetricsEvent.SCREEN);
- proto.setType(state ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
- proto.setTimestamp(eventTimeMs);
- proto.setSubtype(why);
- logger.addEvent(proto);
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- } else if (debug) {
- Log.w(TAG, "wrong number of operands: " + operands.length);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
deleted file mode 100644
index 0c77b7a6ccd0..000000000000
--- a/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-
-/**
- * ...and one parser to rule them all.
- *
- * This should, at some point in the future, be the only parser.
- * @hide
- */
-public class SysuiMultiActionParser extends TagParser {
- private static final String TAG = "SysuiMultiActionParser";
- private static final int EVENTLOG_TAG = 524292;
-
- @Override
- public int getTag() {
- return EVENTLOG_TAG;
- }
-
- @Override
- public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
- final boolean debug = Util.debug();
- try {
- logger.addEvent(new LogMaker(operands).setTimestamp(eventTimeMs));
- } catch (ClassCastException e) {
- if (debug) {
- Log.e(TAG, "unexpected operand type: ", e);
- }
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/TagParser.java b/core/java/com/android/internal/logging/legacy/TagParser.java
deleted file mode 100755
index 3bffdd522236..000000000000
--- a/core/java/com/android/internal/logging/legacy/TagParser.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.util.Log;
-
-import android.metrics.LogMaker;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-/**
- * Abstraction layer between EventLog static classes and the actual TagParsers.
- * @hide
- */
-public abstract class TagParser {
- private static final String TAG = "TagParser";
-
- protected int mSinceCreationMillis;
- protected int mSinceUpdateMillis;
- protected int mSinceVisibleMillis;
-
- abstract int getTag();
-
- @VisibleForTesting
- abstract public void parseEvent(TronLogger logger, long eventTimeMs, Object[] objects);
-
- /**
- * Parse the event into the proto: return true if proto was modified.
- */
- public void parseEvent(TronLogger logger, EventLogCollector.Event event) {
- final boolean debug = Util.debug();
- Object data = event.getData();
- Object[] objects;
- if (data instanceof Object[]) {
- objects = (Object[]) data;
- for (int i = 0; i < objects.length; i++) {
- if (objects[i] == null) {
- if (debug) {
- Log.d(TAG, "unexpected null value:" + event.getTag());
- }
- return;
- }
- }
- } else {
- // wrap scalar objects
- objects = new Object[1];
- objects[0] = data;
- }
-
- parseEvent(logger, event.getTimeNanos() / 1000000, objects);
- }
-
- protected void resetTimes() {
- mSinceCreationMillis = 0;
- mSinceUpdateMillis = 0;
- mSinceVisibleMillis = 0;
- }
-
- public void parseTimes(Object[] operands, int index) {
- resetTimes();
-
- if (operands.length > index && operands[index] instanceof Integer) {
- mSinceCreationMillis = (Integer) operands[index];
- }
-
- index++;
- if (operands.length > index && operands[index] instanceof Integer) {
- mSinceUpdateMillis = (Integer) operands[index];
- }
-
- index++;
- if (operands.length > index && operands[index] instanceof Integer) {
- mSinceVisibleMillis = (Integer) operands[index];
- }
- }
-
- public void filltimes(LogMaker proto) {
- if (mSinceCreationMillis != 0) {
- proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS,
- mSinceCreationMillis);
- }
- if (mSinceUpdateMillis != 0) {
- proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS,
- mSinceUpdateMillis);
- }
- if (mSinceVisibleMillis != 0) {
- proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS,
- mSinceVisibleMillis);
- }
- }
-}
diff --git a/core/java/com/android/internal/logging/legacy/TronCounters.java b/core/java/com/android/internal/logging/legacy/TronCounters.java
deleted file mode 100644
index e0828a20d6ad..000000000000
--- a/core/java/com/android/internal/logging/legacy/TronCounters.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-/**
- * Names of the counters that the Tron package defines.
- *
- * Other counter names may be generated by AOSP code.
- * @hide
- */
-public class TronCounters {
-
- static final String TRON_COLLECTIONS = "tron_collections";
-
- static final String TRON_COLLECTION_PERIOD = "tron_collection_period_minutes";
-
- static final String TRON_EVENTLOG_LENGTH = "tron_eventlog_horizon";
-
- static final String TRON_NOTE_DISMISS = "tron_note_dismiss";
-
- static final String TRON_NOTE_DISMISS_BY_USER = "tron_note_dismiss_user";
-
- static final String TRON_NOTE_DISMISS_BY_CLICK = "tron_note_dismiss_click";
-
- static final String TRON_NOTE_DISMISS_BY_LISTENER = "tron_note_dismiss_listener";
-
- static final String TRON_NOTE_DISMISS_BY_BAN = "tron_note_dismiss_ban";
-
- static final String TRON_NOTE_REVEALED = "tron_note_revealed";
-
- static final String TRON_NOTIFICATION_LOAD = "tron_notification_load";
-
- static final String TRON_VIEW = "tron_view";
-
- static final String TRON_ACTION = "tron_action";
-
- static final String TRON_DETAIL = "tron_detail";
-
- static final String TRON_NOTE_LIFETIME = "tron_note_lifetime";
-
- /** Append the AOSP-generated name */
- static final String TRON_AOSP_PREFIX = "tron_varz_";
-
- static final String TRON_ACTION_BAD_INT = "tron_action_bad_int";
-
- static final String TRON_NOTE_FRESHNESS = "tron_note_freshness";
-
- static final String TRON_NOTE_BUZZ = "tron_note_buzz";
-
- static final String TRON_NOTE_BEEP = "tron_note_beep";
-
- static final String TRON_NOTE_BLINK = "tron_note_blink";
-
- static final String TRON_DISABLE = "tron_disable";
-
- static final String TRON_LAST_HEART_AGE = "tron_last_heart_minutes";
-
- static final String TRON_HEARTS_SEEN = "tron_hearts_seen";
-}
diff --git a/core/java/com/android/internal/logging/legacy/TronLogger.java b/core/java/com/android/internal/logging/legacy/TronLogger.java
deleted file mode 100644
index ee9341ab2138..000000000000
--- a/core/java/com/android/internal/logging/legacy/TronLogger.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-import android.metrics.LogMaker;
-
-/**
- * An entity that knows how to log events and counters.
- */
-public interface TronLogger {
- /** Add one to the named counter. */
- void increment(String counterName);
-
- /** Add an arbitrary value to the named counter. */
- void incrementBy(String counterName, int value);
-
- /** Increment a specified bucket on the named histogram by one. */
- void incrementIntHistogram(String counterName, int bucket);
-
- /** Increment the specified bucket on the named histogram by one. */
- void incrementLongHistogram(String counterName, long bucket);
-
- /** Obtain a SystemUiEvent proto, must release this with dispose() or addEvent(). */
- LogMaker obtain();
-
- void dispose(LogMaker proto);
-
- /** Submit an event to be logged. Logger will dispose of proto. */
- void addEvent(LogMaker proto);
-
- /** Get a config flag. */
- boolean getConfig(String configName);
-
- /** Set a config flag. */
- void setConfig(String configName, boolean newValue);
-}
diff --git a/core/java/com/android/internal/logging/legacy/Util.java b/core/java/com/android/internal/logging/legacy/Util.java
deleted file mode 100644
index 99f71caf5d29..000000000000
--- a/core/java/com/android/internal/logging/legacy/Util.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.logging.legacy;
-
-/**
- * Created by cwren on 11/21/16.
- */
-public class Util {
- public static boolean debug() {
- return false;
- }
-}
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 040f150e8c95..f88ac495fe52 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -18,9 +18,11 @@ package com.android.internal.policy;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.util.Size;
import android.view.Gravity;
import android.view.ViewConfiguration;
import android.widget.Scroller;
@@ -56,6 +58,10 @@ public class PipSnapAlgorithm {
private final int mDefaultSnapMode = SNAP_MODE_CORNERS_AND_EDGES;
private int mSnapMode = mDefaultSnapMode;
+ private final float mDefaultSizePercent;
+ private final float mMinAspectRatioForMinSize;
+ private final float mMaxAspectRatioForMinSize;
+
private Scroller mScroller;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -63,9 +69,15 @@ public class PipSnapAlgorithm {
private boolean mIsMinimized;
public PipSnapAlgorithm(Context context) {
+ Resources res = context.getResources();
mContext = context;
- mMinimizedVisibleSize = context.getResources().getDimensionPixelSize(
+ mMinimizedVisibleSize = res.getDimensionPixelSize(
com.android.internal.R.dimen.pip_minimized_visible_size);
+ mDefaultSizePercent = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
+ mMaxAspectRatioForMinSize = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
+ mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
onConfigurationChanged();
}
@@ -242,6 +254,40 @@ public class PipSnapAlgorithm {
}
/**
+ * @return the size of the PiP at the given {@param aspectRatio}, ensuring that the minimum edge
+ * is at least {@param minEdgeSize}.
+ */
+ public Size getSizeForAspectRatio(float aspectRatio, float minEdgeSize, int displayWidth,
+ int displayHeight) {
+ final int smallestDisplaySize = Math.min(displayWidth, displayHeight);
+ final int minSize = (int) Math.max(minEdgeSize, smallestDisplaySize * mDefaultSizePercent);
+
+ final int width;
+ final int height;
+ if (aspectRatio <= mMinAspectRatioForMinSize || aspectRatio > mMaxAspectRatioForMinSize) {
+ // Beyond these points, we can just use the min size as the shorter edge
+ if (aspectRatio <= 1) {
+ // Portrait, width is the minimum size
+ width = minSize;
+ height = Math.round(width / aspectRatio);
+ } else {
+ // Landscape, height is the minimum size
+ height = minSize;
+ width = Math.round(height * aspectRatio);
+ }
+ } else {
+ // Within these points, we ensure that the bounds fit within the radius of the limits
+ // at the points
+ final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
+ final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
+ height = (int) Math.round(Math.sqrt((radius * radius) /
+ (aspectRatio * aspectRatio + 1)));
+ width = Math.round(height * aspectRatio);
+ }
+ return new Size(width, height);
+ }
+
+ /**
* @return the closest point in {@param points} to the given {@param x} and {@param y}.
*/
private Point findClosestPoint(int x, int y, Point[] points) {
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index f4f49b1e4ffe..c64ace403f76 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -59,4 +61,10 @@ public class NotificationExpandButton extends ImageView {
rect.top = rect.centerY() - touchTargetSize / 2;
rect.bottom = rect.top + touchTargetSize;
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(Button.class.getName());
+ }
}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 90ed6eb5e60e..4a445d8705ca 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -121,7 +121,8 @@ static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
b->finish();
}
-static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset) {
+static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset,
+ jint minPrefix, jint minSuffix) {
const uint8_t* bytebuf = nullptr;
if (buffer != nullptr) {
void* rawbuf = env->GetDirectBufferAddress(buffer);
@@ -131,7 +132,8 @@ static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset) {
ALOGE("failed to get direct buffer address");
}
}
- minikin::Hyphenator* hyphenator = minikin::Hyphenator::loadBinary(bytebuf);
+ minikin::Hyphenator* hyphenator = minikin::Hyphenator::loadBinary(
+ bytebuf, minPrefix, minSuffix);
return reinterpret_cast<jlong>(hyphenator);
}
@@ -191,7 +193,7 @@ static const JNINativeMethod gMethods[] = {
{"nNewBuilder", "()J", (void*) nNewBuilder},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
- {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;I)J", (void*) nLoadHyphenator},
+ {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;III)J", (void*) nLoadHyphenator},
{"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
{"nSetupParagraph", "(J[CIFIF[IIIIZ)V", (void*) nSetupParagraph},
{"nSetIndents", "(J[I)V", (void*) nSetIndents},
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 0dfeb6286fb3..448cd2e30ef4 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -97,7 +97,7 @@
android:layout_height="wrap_content"
android:paddingTop="1dp"
android:visibility="gone"
- android:contentDescription="@string/expand_button_content_description"
+ android:contentDescription="@string/expand_button_content_description_collapsed"
/>
<ImageView android:id="@+id/profile_badge"
android:layout_width="@dimen/notification_badge_size"
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index c27cb06deb8d..1987ac454d86 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -24,9 +24,10 @@
<!-- Flags enabling default window features. See Window.java -->
<bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
- <!-- Max default size [WIDTHxHEIGHT] on screen for picture-in-picture windows to fit inside.
- These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureSize">240x135</string>
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.14</item>
<!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
These values are in DPs and will be converted to pixel sizes internally. -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2e09e7d1b0c5..f8d5241b8467 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3336,7 +3336,7 @@
{@link android.accessibilityservice.AccessibilityService#SERVICE_META_DATA}
meta-data entry. -->
<declare-styleable name="AccessibilityService">
- <!-- The event types this serivce would like to receive as specified in
+ <!-- The event types this service would like to receive as specified in
{@link android.view.accessibility.AccessibilityEvent}. This setting
can be changed at runtime by calling
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
@@ -3395,11 +3395,11 @@
<!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPES_ALL_MASK} i.e. all events. -->
<flag name="typeAllMask" value="0xffffffff" />
</attr>
- <!-- Comma separated package names from which this serivce would like to receive events (leave out for all packages).
+ <!-- Comma separated package names from which this service would like to receive events (leave out for all packages).
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="packageNames" format="string" />
- <!-- The feedback types this serivce provides as specified in
+ <!-- The feedback types this service provides as specified in
{@link android.accessibilityservice.AccessibilityServiceInfo}. This setting
can be changed at runtime by calling
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
@@ -3419,7 +3419,7 @@
<flag name="feedbackAllMask" value="0xffffffff" />
</attr>
<!-- The minimal period in milliseconds between two accessibility events of the same type
- are sent to this serivce. This setting can be changed at runtime by calling
+ are sent to this service. This setting can be changed at runtime by calling
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="notificationTimeout" format="integer" />
@@ -3498,6 +3498,8 @@
<attr name="canCaptureFingerprintGestures" format="boolean" />
<!-- Short description of the accessibility service purpose or behavior.-->
<attr name="description" />
+ <!-- Brief summary of the accessibility service purpose or behavior. -->
+ <attr name="summary" />
</declare-styleable>
<!-- Use <code>print-service</code> as the root tag of the XML resource that
@@ -8565,6 +8567,7 @@
<!-- Attributes that are read when parsing a <fontfamily> tag. -->
<declare-styleable name="FontFamily">
<attr name="fontProviderAuthority" format="string" />
+ <attr name="fontProviderPackage" format="string" />
<attr name="fontProviderQuery" format="string" />
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ab2e090b2869..a3a0c830a0cf 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2545,9 +2545,17 @@
These values are in DPs and will be converted to pixel sizes internally. -->
<string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
- <!-- Max default size [WIDTHxHEIGHT] on screen for picture-in-picture windows to fit inside.
- These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureSize">192x120</string>
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.23</item>
+
+ <!-- The default aspect ratio for picture-in-picture windows. -->
+ <item name="config_pictureInPictureDefaultAspectRatio" format="float" type="dimen">1.777778</item>
+
+ <!-- This is the limit for the max and min aspect ratio (1 / this value) at which the min size
+ will be used instead of an adaptive size based loosely on area. -->
+ <item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0ab17842ebb7..d0127a3a6cd6 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -486,6 +486,9 @@
<!-- The default minimal size of a resizable task, in both dimensions. -->
<dimen name="default_minimal_size_resizable_task">220dp</dimen>
+ <!-- The default minimal size of a PiP task, in both dimensions. -->
+ <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
+
<!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
<dimen name="task_height_of_minimized_mode">80dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index df3962c5dd5c..0d90cd2f9b44 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2802,6 +2802,7 @@
<public name="requiredFeature" />
<public name="requiredNotFeature" />
<public name="autoFillHint" />
+ <public name="fontProviderPackage" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ea0666413f88..bd8d5724ac50 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4382,8 +4382,11 @@
<!-- Content description of the work profile icon in the notification. -->
<string name="notification_work_profile_content_description">Work profile</string>
- <!-- Content description of the expand button icon in the notification.-->
- <string name="expand_button_content_description">Expand button</string>
+ <!-- Content description of the expand button icon in the notification when collaped.-->
+ <string name="expand_button_content_description_collapsed">Expand</string>
+
+ <!-- Content description of the expand button icon in the notification when expanded.-->
+ <string name="expand_button_content_description_expanded">Collapse</string>
<!-- Accessibility action description on the expand button. -->
<string name="expand_action_accessibility">toggle expansion</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3ba6a274ee8a..32babab658bb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -318,7 +318,9 @@
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
<java-symbol type="bool" name="config_enableAppWidgetService" />
<java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
- <java-symbol type="string" name="config_defaultPictureInPictureSize" />
+ <java-symbol type="dimen" name="config_pictureInPictureDefaultSizePercent" />
+ <java-symbol type="dimen" name="config_pictureInPictureDefaultAspectRatio" />
+ <java-symbol type="dimen" name="config_pictureInPictureAspectRatioLimitForMinSize" />
<java-symbol type="integer" name="config_defaultPictureInPictureGravity" />
<java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" />
<java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" />
@@ -1777,6 +1779,7 @@
<java-symbol type="id" name="replace_message" />
<java-symbol type="fraction" name="config_dimBehindFadeDuration" />
<java-symbol type="dimen" name="default_minimal_size_resizable_task" />
+ <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" />
<java-symbol type="dimen" name="task_height_of_minimized_mode" />
<java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
<java-symbol type="fraction" name="config_autoBrightnessAdjustmentMaxGamma" />
@@ -2885,6 +2888,9 @@
<java-symbol type="style" name="Widget.LockPatternView" />
<java-symbol type="attr" name="lockPatternStyle" />
+ <java-symbol type="string" name="expand_button_content_description_collapsed" />
+ <java-symbol type="string" name="expand_button_content_description_expanded" />
+
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
diff --git a/core/tests/coretests/res/font/samplexmldownloadedfont.xml b/core/tests/coretests/res/font/samplexmldownloadedfont.xml
index 35391bd598b3..f1bdc473b9d2 100644
--- a/core/tests/coretests/res/font/samplexmldownloadedfont.xml
+++ b/core/tests/coretests/res/font/samplexmldownloadedfont.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
- android:fontProviderAuthority="com.example.test.fontprovider"
+ android:fontProviderAuthority="com.example.test.fontprovider.authority"
+ android:fontProviderPackage="com.example.test.fontprovider.package"
android:fontProviderQuery="MyRequestedFont">
</font-family> \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 8b536a7a90b5..23d3aa5a64ab 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -91,7 +91,8 @@ public class FontResourcesParserTest {
List<FontConfig.Family> families = result.getFamilies();
assertEquals(1, families.size());
FontConfig.Family family = families.get(0);
- assertEquals("com.example.test.fontprovider", family.getProviderAuthority());
+ assertEquals("com.example.test.fontprovider.authority", family.getProviderAuthority());
+ assertEquals("com.example.test.fontprovider.package", family.getProviderPackage());
assertEquals("MyRequestedFont", family.getQuery());
assertNull(family.getFonts());
}
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index b9c973fb09cd..ece44bebf9ba 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -122,6 +122,55 @@ public class LogMakerTest extends TestCase {
assertEquals(null, builder.getTaggedData(1));
}
+ public void testClearFieldLeavesOtherFieldsIntact() {
+ LogMaker builder = new LogMaker(0);
+ builder.setPackageName("package.name");
+ builder.setSubtype(10);
+ builder.clearPackageName();
+ assertEquals(null, builder.getPackageName());
+ assertEquals(10, builder.getSubtype());
+ }
+
+ public void testSetAndClearCategory() {
+ LogMaker builder = new LogMaker(0);
+ builder.setCategory(MetricsEvent.MAIN_SETTINGS);
+ assertEquals(MetricsEvent.MAIN_SETTINGS, builder.getCategory());
+ builder.clearCategory();
+ assertEquals(MetricsEvent.VIEW_UNKNOWN, builder.getCategory());
+ }
+
+ public void testSetAndClearType() {
+ LogMaker builder = new LogMaker(0);
+ builder.setType(MetricsEvent.TYPE_OPEN);
+ assertEquals(MetricsEvent.TYPE_OPEN, builder.getType());
+ builder.clearType();
+ assertEquals(MetricsEvent.TYPE_UNKNOWN, builder.getType());
+ }
+
+ public void testSetAndClearSubtype() {
+ LogMaker builder = new LogMaker(0);
+ builder.setSubtype(1);
+ assertEquals(1, builder.getSubtype());
+ builder.clearSubtype();
+ assertEquals(0, builder.getSubtype());
+ }
+
+ public void testSetAndClearTimestamp() {
+ LogMaker builder = new LogMaker(0);
+ builder.setTimestamp(1);
+ assertEquals(1, builder.getTimestamp());
+ builder.clearTimestamp();
+ assertEquals(0, builder.getTimestamp());
+ }
+
+ public void testSetAndClearPackageName() {
+ LogMaker builder = new LogMaker(0);
+ builder.setPackageName("package.name");
+ assertEquals("package.name", builder.getPackageName());
+ builder.clearPackageName();
+ assertEquals(null, builder.getPackageName());
+ }
+
public void testGiantLogOmitted() {
LogMaker badBuilder = new LogMaker(0);
StringBuilder b = new StringBuilder();
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
new file mode 100644
index 000000000000..db623a4a2044
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.provider;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.Signature;
+import android.graphics.Typeface;
+import android.graphics.fonts.FontRequest;
+import android.graphics.fonts.FontResult;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.support.test.filters.SmallTest;
+import android.test.ProviderTestCase2;
+import android.util.Base64;
+
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link FontsContract}.
+ */
+@SmallTest
+public class FontsContractTest extends ProviderTestCase2<TestFontsProvider> {
+ private static final byte[] BYTE_ARRAY =
+ Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
+ private static final String PACKAGE_NAME = "com.my.font.provider.package";
+
+ private final FontRequest request = new FontRequest(
+ TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query");
+ private TestFontsProvider mProvider;
+ private FontsContract mContract;
+ private ResultReceiver mResultReceiver;
+ private PackageManager mPackageManager;
+
+ public FontsContractTest() {
+ super(TestFontsProvider.class, TestFontsProvider.AUTHORITY);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mProvider = getProvider();
+ mPackageManager = mock(PackageManager.class);
+ mContract = new FontsContract(getMockContext(), mPackageManager);
+ mResultReceiver = mock(ResultReceiver.class);
+ }
+
+ public void testGetFontFromProvider() {
+ mContract.getFontFromProvider(request, mResultReceiver, TestFontsProvider.AUTHORITY);
+
+ final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mResultReceiver).send(eq(FontsContract.RESULT_CODE_OK), bundleCaptor.capture());
+
+ Bundle bundle = bundleCaptor.getValue();
+ assertNotNull(bundle);
+ List<FontResult> resultList =
+ bundle.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
+ assertNotNull(resultList);
+ assertEquals(1, resultList.size());
+ FontResult fontResult = resultList.get(0);
+ assertEquals(TestFontsProvider.TTC_INDEX, fontResult.getTtcIndex());
+ assertEquals(TestFontsProvider.VARIATION_SETTINGS, fontResult.getFontVariationSettings());
+ assertEquals(TestFontsProvider.STYLE, fontResult.getStyle());
+ assertNotNull(fontResult.getFileDescriptor());
+ }
+
+ public void testGetFontFromProvider_providerDoesntReturnAllFields() {
+ mProvider.setReturnAllFields(false);
+
+ final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ mContract.getFontFromProvider(request, mResultReceiver, TestFontsProvider.AUTHORITY);
+ verify(mResultReceiver).send(eq(FontsContract.RESULT_CODE_OK), bundleCaptor.capture());
+
+ Bundle bundle = bundleCaptor.getValue();
+ assertNotNull(bundle);
+ List<FontResult> resultList =
+ bundle.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
+ assertNotNull(resultList);
+ assertEquals(1, resultList.size());
+ FontResult fontResult = resultList.get(0);
+ assertEquals(0, fontResult.getTtcIndex());
+ assertNull(fontResult.getFontVariationSettings());
+ assertEquals(Typeface.NORMAL, fontResult.getStyle());
+ assertNotNull(fontResult.getFileDescriptor());
+ }
+
+ public void testGetProvider_providerNotFound() {
+ when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(null);
+
+ ProviderInfo result = mContract.getProvider(request);
+
+ assertNull(result);
+ }
+
+ public void testGetProvider_providerIsSystemApp() throws PackageManager.NameNotFoundException {
+ ProviderInfo info = setupPackageManager();
+ info.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
+
+ ProviderInfo result = mContract.getProvider(request);
+
+ assertEquals(info, result);
+ }
+
+ public void testGetProvider_providerIsSystemAppWrongPackage()
+ throws PackageManager.NameNotFoundException {
+ ProviderInfo info = setupPackageManager();
+ info.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
+
+ ProviderInfo result = mContract.getProvider(
+ new FontRequest(TestFontsProvider.AUTHORITY, "com.wrong.package", "query"));
+
+ assertNull(result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppNoCerts()
+ throws PackageManager.NameNotFoundException {
+ setupPackageManager();
+
+ // The default request is missing the certificates info.
+ ProviderInfo result = mContract.getProvider(request);
+
+ assertNull(result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppWrongCerts()
+ throws PackageManager.NameNotFoundException {
+ setupPackageManager();
+
+ byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
+ List<byte[]> certList = Arrays.asList(wrongCert);
+ FontRequest requestWrongCerts = new FontRequest(
+ TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+ ProviderInfo result = mContract.getProvider(requestWrongCerts);
+
+ assertNull(result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppCorrectCerts()
+ throws PackageManager.NameNotFoundException {
+ ProviderInfo info = setupPackageManager();
+
+ List<byte[]> certList = Arrays.asList(BYTE_ARRAY);
+ FontRequest requestRightCerts = new FontRequest(
+ TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+ ProviderInfo result = mContract.getProvider(requestRightCerts);
+
+ assertEquals(info, result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppMoreCerts()
+ throws PackageManager.NameNotFoundException {
+ setupPackageManager();
+
+ byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
+ List<byte[]> certList = Arrays.asList(wrongCert, BYTE_ARRAY);
+ FontRequest requestRightCerts = new FontRequest(
+ TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+ ProviderInfo result = mContract.getProvider(requestRightCerts);
+
+ // There is one too many certs, should fail as the set doesn't match.
+ assertNull(result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppCorrectCertsSeveralSets()
+ throws PackageManager.NameNotFoundException {
+ ProviderInfo info = setupPackageManager();
+
+ List<List<byte[]>> certList = new ArrayList<>();
+ byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
+ certList.add(Arrays.asList(wrongCert));
+ certList.add(Arrays.asList(BYTE_ARRAY));
+ FontRequest requestRightCerts = new FontRequest(
+ TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", certList);
+ ProviderInfo result = mContract.getProvider(requestRightCerts);
+
+ assertEquals(info, result);
+ }
+
+ public void testGetProvider_providerIsNonSystemAppWrongPackage()
+ throws PackageManager.NameNotFoundException {
+ setupPackageManager();
+
+ List<List<byte[]>> certList = new ArrayList<>();
+ certList.add(Arrays.asList(BYTE_ARRAY));
+ FontRequest requestRightCerts = new FontRequest(
+ TestFontsProvider.AUTHORITY, "com.wrong.package.name", "query", certList);
+ ProviderInfo result = mContract.getProvider(requestRightCerts);
+
+ assertNull(result);
+ }
+
+ private ProviderInfo setupPackageManager()
+ throws PackageManager.NameNotFoundException {
+ ProviderInfo info = new ProviderInfo();
+ info.packageName = PACKAGE_NAME;
+ info.applicationInfo = new ApplicationInfo();
+ when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
+ PackageInfo packageInfo = new PackageInfo();
+ Signature signature = mock(Signature.class);
+ when(signature.toByteArray()).thenReturn(BYTE_ARRAY);
+ packageInfo.packageName = PACKAGE_NAME;
+ packageInfo.signatures = new Signature[] { signature };
+ when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
+ return info;
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/TestFontsProvider.java b/core/tests/coretests/src/android/provider/TestFontsProvider.java
new file mode 100644
index 000000000000..6d40f37af548
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/TestFontsProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.provider;
+
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Provides a test Content Provider implementing {@link FontsContract}.
+ */
+public class TestFontsProvider extends ContentProvider {
+ static final String AUTHORITY = "android.provider.TestFontsProvider";
+ static final int TTC_INDEX = 2;
+ static final String VARIATION_SETTINGS = "'wdth' 1";
+ static final int STYLE = Typeface.BOLD;
+
+ private ParcelFileDescriptor mPfd;
+ private boolean mReturnAllFields = true;
+
+ /**
+ * Used by tests to switch whether all fields should be returned or not.
+ */
+ void setReturnAllFields(boolean returnAllFields) {
+ mReturnAllFields = returnAllFields;
+ }
+
+ @Override
+ public boolean onCreate() {
+ mPfd = createFontFile();
+ return true;
+ }
+
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
+ @Nullable String[] selectionArgs, @Nullable String sortOrder) {
+ MatrixCursor cursor;
+ if (mReturnAllFields) {
+ cursor = new MatrixCursor(new String[] { FontsContract.Columns._ID,
+ FontsContract.Columns.TTC_INDEX, FontsContract.Columns.VARIATION_SETTINGS,
+ FontsContract.Columns.STYLE });
+ cursor.addRow(new Object[] { 1, TTC_INDEX, VARIATION_SETTINGS, STYLE });
+ } else {
+ cursor = new MatrixCursor(new String[] { FontsContract.Columns._ID });
+ cursor.addRow(new Object[] { 1 });
+ }
+ return cursor;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ try {
+ return mPfd.dup();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return "application/x-font-ttf";
+ }
+
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return 0;
+ }
+
+ private ParcelFileDescriptor createFontFile() {
+ try {
+ final File file = new File(getContext().getCacheDir(), "font.ttf");
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ return ParcelFileDescriptor.open(file, MODE_READ_ONLY);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 52e18a9095cf..8b309035c013 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -186,8 +186,8 @@ public class Typeface {
}
// Downloaded font and it wasn't cached, request it again and return a
// default font instead (nothing we can do now).
- create(new FontRequest(family.getProviderAuthority(), family.getQuery()),
- NO_OP_REQUEST_CALLBACK);
+ create(new FontRequest(family.getProviderAuthority(), family.getProviderPackage(),
+ family.getQuery()), NO_OP_REQUEST_CALLBACK);
return DEFAULT;
}
diff --git a/graphics/java/android/graphics/fonts/FontRequest.java b/graphics/java/android/graphics/fonts/FontRequest.java
index e50df6faa38e..c7a583056b76 100644
--- a/graphics/java/android/graphics/fonts/FontRequest.java
+++ b/graphics/java/android/graphics/fonts/FontRequest.java
@@ -18,24 +18,56 @@ package android.graphics.fonts;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Base64;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* Information about a font request that may be sent to a Font Provider.
*/
public final class FontRequest implements Parcelable {
private final String mProviderAuthority;
+ private final String mProviderPackage;
private final String mQuery;
+ private final List<List<byte[]>> mCertificates;
+
+ /**
+ * @param providerAuthority The authority of the Font Provider to be used for the request. This
+ * should be a system installed app.
+ * @param providerPackage The package for the Font Provider to be used for the request. This is
+ * used to verify the identity of the provider.
+ * @param query The query to be sent over to the provider. Refer to your font provider's
+ * documentation on the format of this string.
+ */
+ public FontRequest(@NonNull String providerAuthority, @NonNull String providerPackage,
+ @NonNull String query) {
+ mProviderAuthority = Preconditions.checkNotNull(providerAuthority);
+ mQuery = Preconditions.checkNotNull(query);
+ mProviderPackage = Preconditions.checkNotNull(providerPackage);
+ mCertificates = Collections.emptyList();
+ }
/**
* @param providerAuthority The authority of the Font Provider to be used for the request.
* @param query The query to be sent over to the provider. Refer to your font provider's
- * documentation on the format of this string.
+ * documentation on the format of this string.
+ * @param providerPackage The package for the Font Provider to be used for the request. This is
+ * used to verify the identity of the provider.
+ * @param certificates The list of sets of hashes for the certificates the provider should be
+ * signed with. This is used to verify the identity of the provider. Each set in the
+ * list represents one collection of signature hashes. Refer to your font provider's
+ * documentation for these values.
*/
- public FontRequest(@NonNull String providerAuthority, @NonNull String query) {
+ public FontRequest(@NonNull String providerAuthority, @NonNull String providerPackage,
+ @NonNull String query, @NonNull List<List<byte[]>> certificates) {
mProviderAuthority = Preconditions.checkNotNull(providerAuthority);
+ mProviderPackage = Preconditions.checkNotNull(providerPackage);
mQuery = Preconditions.checkNotNull(query);
+ mCertificates = Preconditions.checkNotNull(certificates);
}
/**
@@ -47,6 +79,14 @@ public final class FontRequest implements Parcelable {
}
/**
+ * Returns the selected font provider's package. This helps the system verify that the provider
+ * identified by the given authority is the one requested.
+ */
+ public String getProviderPackage() {
+ return mProviderPackage;
+ }
+
+ /**
* Returns the query string. Refer to your font provider's documentation on the format of this
* string.
*/
@@ -54,6 +94,14 @@ public final class FontRequest implements Parcelable {
return mQuery;
}
+ /**
+ * Returns the list of certificate sets given for this provider. This helps the system verify
+ * that the provider identified by the given authority is the one requested.
+ */
+ public List<List<byte[]>> getCertificates() {
+ return mCertificates;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -62,12 +110,17 @@ public final class FontRequest implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mProviderAuthority);
+ dest.writeString(mProviderPackage);
dest.writeString(mQuery);
+ dest.writeList(mCertificates);
}
private FontRequest(Parcel in) {
mProviderAuthority = in.readString();
+ mProviderPackage = in.readString();
mQuery = in.readString();
+ mCertificates = new ArrayList<>();
+ in.readList(mCertificates, null);
}
public static final Parcelable.Creator<FontRequest> CREATOR =
@@ -85,9 +138,24 @@ public final class FontRequest implements Parcelable {
@Override
public String toString() {
- return "FontRequest {"
+ StringBuilder builder = new StringBuilder();
+ builder.append("FontRequest {"
+ "mProviderAuthority: " + mProviderAuthority
+ + ", mProviderPackage: " + mProviderPackage
+ ", mQuery: " + mQuery
- + "}";
+ + ", mCertificates:");
+ for (int i = 0; i < mCertificates.size(); i++) {
+ builder.append(" [");
+ List<byte[]> set = mCertificates.get(i);
+ for (int j = 0; j < set.size(); j++) {
+ builder.append(" \"");
+ byte[] array = set.get(j);
+ builder.append(Base64.encodeToString(array, Base64.DEFAULT));
+ builder.append("\"");
+ }
+ builder.append(" ]");
+ }
+ builder.append("}");
+ return builder.toString();
}
}
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 9f98241c6caa..9823a02dc847 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -31,7 +31,7 @@ static int computeClipSideFlags(const Rect& clip, const Rect& bounds) {
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke) {
+ const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) {
// resolvedMatrix = parentMatrix * localMatrix
transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
@@ -40,6 +40,8 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
if (CC_UNLIKELY(expandForStroke)) {
// account for non-hairline stroke
clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+ } else if (CC_UNLIKELY(expandForPathTexture)) {
+ clippedBounds.outset(1);
}
transform.mapRect(clippedBounds);
if (CC_UNLIKELY(expandForStroke
@@ -111,7 +113,7 @@ BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
Snapshot& snapshot, const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, false);
+ allocator, snapshot, recordedOp, false, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -127,14 +129,14 @@ BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
}
BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
+ bool expandForPathTexture) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
- ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
- : true;
+ bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced
+ || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, expandForStroke);
+ allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
// NOTE: this won't succeed if a clip was allocated
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index e1441fca5ee2..7b0b34f3d9c0 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -53,7 +53,7 @@ struct MergedBakedOpList {
class ResolvedRenderState {
public:
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke);
+ const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture);
// Constructor for unbounded ops *with* transform/clip
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
@@ -117,7 +117,8 @@ public:
};
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior);
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
+ bool expandForPathTexture);
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
Snapshot& snapshot, const ShadowOp* shadowOpPtr);
@@ -140,8 +141,8 @@ private:
friend class LinearAllocator;
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke)
- : computedState(allocator, snapshot, recordedOp, expandForStroke)
+ const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture)
+ : computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
, op(&recordedOp) {}
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 1b57e290c198..86f9a5d73fd1 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -562,10 +562,11 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
* for paint's style on the bounds being computed.
*/
BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior) {
+ BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
- mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
+ mAllocator, *mCanvasState.writableSnapshot(), op,
+ strokeBehavior, expandForPathTexture);
if (!bakedState) return nullptr; // quick rejected
if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
@@ -590,7 +591,10 @@ static batchid_t tessBatchId(const RecordedOp& op) {
}
void FrameBuilder::deferArcOp(const ArcOp& op) {
- deferStrokeableOp(op, tessBatchId(op));
+ // Pass true below since arcs have a tendency to draw outside their expected bounds within
+ // their path textures. Passing true makes it more likely that we'll scissor, instead of
+ // corrupting the frame by drawing outside of clip bounds.
+ deferStrokeableOp(op, tessBatchId(op), BakedOpState::StrokeBehavior::StyleDefined, true);
}
static bool hasMergeableClip(const BakedOpState& state) {
@@ -748,7 +752,7 @@ static batchid_t textBatchId(const SkPaint& paint) {
void FrameBuilder::deferTextOp(const TextOp& op) {
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), op,
- BakedOpState::StrokeBehavior::StyleDefined);
+ BakedOpState::StrokeBehavior::StyleDefined, false);
if (!bakedState) return; // quick rejected
batchid_t batchId = textBatchId(*(op.paint));
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index b9154435c1e5..46048f7125ce 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -211,7 +211,8 @@ private:
}
BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
+ BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined,
+ bool expandForPathTexture = false);
/**
* Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index 0f8e0471556f..d51db2ebb169 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -35,7 +35,7 @@ TEST(ResolvedRenderState, construct) {
{
// recorded with transform, no parent transform
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
- ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
EXPECT_EQ(Rect(100, 200), state.clipRect());
EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
@@ -44,7 +44,7 @@ TEST(ResolvedRenderState, construct) {
{
// recorded with transform and parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
Matrix4 expectedTranslate;
expectedTranslate.loadTranslate(20, 40, 0);
@@ -70,14 +70,14 @@ TEST(ResolvedRenderState, computeLocalSpaceClip) {
{
// recorded with transform, no parent transform
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
- ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
<< "Local clip rect should be 100x200, offset by -10,-20";
}
{
// recorded with transform + parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
<< "Local clip rect should be 90x190, offset by -10,-20";
}
@@ -170,7 +170,7 @@ TEST(ResolvedRenderState, construct_expandForStroke) {
snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
- ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true, false);
testCase.validator(state);
}
}
@@ -234,7 +234,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined);
+ BakedOpState::StrokeBehavior::StyleDefined, false);
EXPECT_EQ(nullptr, bakedState);
EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
@@ -248,7 +248,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined);
+ BakedOpState::StrokeBehavior::StyleDefined, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
@@ -263,7 +263,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::Forced);
+ BakedOpState::StrokeBehavior::Forced, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 95d9459e898c..a329980b7609 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -171,6 +171,35 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
EXPECT_EQ(1, renderer.getIndex());
}
+
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
+ class ArcStrokeClipTestRenderer : public TestRendererBase {
+ public:
+ void onArcOp(const ArcOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(25, 25, 175, 175), op.unmappedBounds);
+ EXPECT_EQ(Rect(25, 25, 175, 175), state.computedState.clippedBounds);
+ EXPECT_EQ(OpClipSideFlags::Full, state.computedState.clipSideFlags)
+ << "Arc op clipped conservatively, since path texture may be expanded";
+ }
+ };
+
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
+ SkPaint aaPaint;
+ aaPaint.setAntiAlias(true);
+ canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
+ ArcStrokeClipTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex());
+}
+
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
[](RenderProperties& props, RecordingCanvas& canvas) {
diff --git a/packages/SystemUI/res/drawable/pip_expand.xml b/packages/SystemUI/res/drawable/pip_expand.xml
new file mode 100644
index 000000000000..e34a95d257ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_expand.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M8,7.5v45c0,2.75,2.25,5,5,5h34.05c2.75,0,4.95-2.25,4.95-5v-45c0-2.75-2.2-5-4.95-5H13
+C10.25,2.5,8,4.75,8,7.5z
+M13,6.5h34c0.55,0,1,0.45,1,1v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45C12,6.95,12.45,6.5,13,6.5z" />
+ <path
+ android:pathData="M60,0L0,0l0,60h60V0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M20.86,35h-2c-0.55,0-1,0.45-1,1v10.5c0,0.55,0.45,1,1,1h10.5c0.55,0,1-0.45,1-1v-2c0-0.55-0.45-1-1-1h-7.5
+V36C21.86,35.45,21.41,35,20.86,35z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M29.64,13.5v2c0,0.55,0.45,1,1,1h7.5V24c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1V13.5c0-0.55-0.45-1-1-1
+h-10.5C30.09,12.5,29.64,12.95,29.64,13.5z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 0f5ca9bdf2fc..f38c8ff5da0c 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -32,19 +32,32 @@
android:background="?android:selectableItemBackgroundBorderless" />
<FrameLayout
+ android:id="@+id/expand_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_gravity="center"
+ android:contentDescription="@string/pip_phone_expand"
+ android:src="@drawable/pip_expand"
+ android:background="?android:selectableItemBackgroundBorderless" />
+ </FrameLayout>
+
+ <FrameLayout
android:id="@+id/actions_container"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
android:background="#66000000"
android:visibility="invisible">
<LinearLayout
- android:id="@+id/actions"
+ android:id="@+id/actions_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
- android:orientation="horizontal" />
+ android:orientation="horizontal"
+ android:divider="@android:color/transparent"
+ android:showDividers="middle" />
</FrameLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3512761afbd2..f331d8782a2d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -731,6 +731,13 @@
<!-- The size of the PIP drag-to-dismiss target. -->
<dimen name="pip_dismiss_target_size">48dp</dimen>
+ <!-- The shortest-edge size of the expanded PiP. -->
+ <dimen name="pip_expanded_shortest_edge_size">160dp</dimen>
+
+ <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
+ the configuration of the device, so we can't use -land resources. -->
+ <dimen name="pip_between_action_padding_land">8dp</dimen>
+
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 5d57daaaf4a1..e38f922c23b4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -53,7 +53,7 @@ public class DozeFactory {
DozeMachine machine = new DozeMachine(
DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params),
- params,
+ config,
wakeLock);
machine.setParts(new DozeMachine.Part[]{
createDozeTriggers(context, sensorManager, host, config, params, handler, wakeLock,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index c9eb790c695e..c852b491feba 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -17,11 +17,12 @@
package com.android.systemui.doze;
import android.annotation.MainThread;
+import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.Preconditions;
-import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
import java.io.PrintWriter;
@@ -95,16 +96,17 @@ public class DozeMachine {
private final Service mDozeService;
private final DozeFactory.WakeLock mWakeLock;
- private final DozeParameters mParams;
+ private final AmbientDisplayConfiguration mConfig;
private Part[] mParts;
private final ArrayList<State> mQueuedRequests = new ArrayList<>();
private State mState = State.UNINITIALIZED;
private boolean mWakeLockHeldForCurrentState = false;
- public DozeMachine(Service service, DozeParameters params, DozeFactory.WakeLock wakeLock) {
+ public DozeMachine(Service service, AmbientDisplayConfiguration config,
+ DozeFactory.WakeLock wakeLock) {
mDozeService = service;
- mParams = params;
+ mConfig = config;
mWakeLock = wakeLock;
}
@@ -267,7 +269,7 @@ public class DozeMachine {
switch (state) {
case INITIALIZED:
case DOZE_PULSE_DONE:
- transitionTo(mParams.getAlwaysOn()
+ transitionTo(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
new file mode 100644
index 000000000000..7a1849ed741e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone;
+
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the input consumer that allows the SystemUI to control the PiP.
+ */
+public class InputConsumerController {
+
+ private static final String TAG = InputConsumerController.class.getSimpleName();
+
+ /**
+ * Listener interface for callers to subscribe to touch events.
+ */
+ public interface TouchListener {
+ boolean onTouchEvent(MotionEvent ev);
+ }
+
+ /**
+ * Input handler used for the PiP input consumer.
+ */
+ private final class PipInputEventReceiver extends InputEventReceiver {
+
+ public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = true;
+ try {
+ // To be implemented for input handling over Pip windows
+ if (mListener != null && event instanceof MotionEvent) {
+ MotionEvent ev = (MotionEvent) event;
+ handled = mListener.onTouchEvent(ev);
+ }
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+ }
+
+ private IWindowManager mWindowManager;
+
+ private PipInputEventReceiver mInputEventReceiver;
+ private TouchListener mListener;
+
+ public InputConsumerController(IWindowManager windowManager) {
+ mWindowManager = windowManager;
+ registerInputConsumer();
+ }
+
+ /**
+ * Sets the touch listener.
+ */
+ public void setTouchListener(TouchListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Registers the input consumer.
+ */
+ public void registerInputConsumer() {
+ if (mInputEventReceiver == null) {
+ final InputChannel inputChannel = new InputChannel();
+ try {
+ mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
+ mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create PIP input consumer", e);
+ }
+ mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper());
+ }
+ }
+
+ /**
+ * Unregisters the input consumer.
+ */
+ public void unregisterInputConsumer() {
+ if (mInputEventReceiver != null) {
+ try {
+ mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to destroy PIP input consumer", e);
+ }
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 714b263e40cc..ecc2fadf5ae2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -53,6 +53,7 @@ public class PipManager implements BasePipManager {
private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
+ private InputConsumerController mInputConsumerController;
private PipMenuActivityController mMenuController;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
@@ -68,6 +69,7 @@ public class PipManager implements BasePipManager {
}
mTouchHandler.onActivityPinned();
mMediaController.onActivityPinned();
+ mMenuController.onActivityPinned();
}
@Override
@@ -120,9 +122,10 @@ public class PipManager implements BasePipManager {
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
- boolean fromImeAdjustement) {
+ Rect animatingBounds, boolean fromImeAdjustement) {
mHandler.post(() -> {
- mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, fromImeAdjustement);
+ mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds,
+ fromImeAdjustement);
});
}
@@ -151,11 +154,12 @@ public class PipManager implements BasePipManager {
}
SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+ mInputConsumerController = new InputConsumerController(mWindowManager);
mMediaController = new PipMediaController(context, mActivityManager);
- mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager,
- mMediaController);
- mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager,
- mWindowManager);
+ mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController,
+ mInputConsumerController);
+ mTouchHandler = new PipTouchHandler(context, mActivityManager, mMenuController,
+ mInputConsumerController);
}
/**
@@ -178,6 +182,7 @@ public class PipManager implements BasePipManager {
public void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
+ mInputConsumerController.dump(pw, innerPrefix);
mMenuController.dump(pw, innerPrefix);
mTouchHandler.dump(pw, innerPrefix);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 4e28061dc21b..65de22e21775 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -40,8 +40,9 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.TextView;
+import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -57,8 +58,9 @@ public class PipMenuActivity extends Activity {
private static final String TAG = "PipMenuActivity";
public static final int MESSAGE_SHOW_MENU = 1;
- public static final int MESSAGE_HIDE_MENU = 2;
- public static final int MESSAGE_UPDATE_ACTIONS = 3;
+ public static final int MESSAGE_POKE_MENU = 2;
+ public static final int MESSAGE_HIDE_MENU = 3;
+ public static final int MESSAGE_UPDATE_ACTIONS = 4;
private static final long INITIAL_DISMISS_DELAY = 2000;
private static final long POST_INTERACTION_DISMISS_DELAY = 1500;
@@ -67,7 +69,9 @@ public class PipMenuActivity extends Activity {
private boolean mMenuVisible;
private final List<RemoteAction> mActions = new ArrayList<>();
private View mMenuContainer;
+ private LinearLayout mActionsGroup;
private View mDismissButton;
+ private int mBetweenActionPaddingLand;
private ObjectAnimator mMenuContainerAnimator;
@@ -83,6 +87,9 @@ public class PipMenuActivity extends Activity {
case MESSAGE_SHOW_MENU:
showMenu();
break;
+ case MESSAGE_POKE_MENU:
+ cancelDelayedFinish();
+ break;
case MESSAGE_HIDE_MENU:
hideMenu();
break;
@@ -127,6 +134,9 @@ public class PipMenuActivity extends Activity {
mDismissButton.setOnClickListener((v) -> {
dismissPip();
});
+ mActionsGroup = (LinearLayout) findViewById(R.id.actions_group);
+ mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
+ R.dimen.pip_between_action_padding_land);
notifyActivityCallback(mMessenger);
showMenu();
@@ -139,6 +149,11 @@ public class PipMenuActivity extends Activity {
}
@Override
+ public void onUserInteraction() {
+ repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ @Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
@@ -164,11 +179,6 @@ public class PipMenuActivity extends Activity {
}
@Override
- public void onUserInteraction() {
- repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
- }
-
- @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// On the first action outside the window, hide the menu
switch (ev.getAction()) {
@@ -177,13 +187,16 @@ public class PipMenuActivity extends Activity {
break;
case MotionEvent.ACTION_DOWN:
mDownPosition.set(ev.getX(), ev.getY());
+ mDownDelta.set(0f, 0f);
break;
case MotionEvent.ACTION_MOVE:
mDownDelta.set(ev.getX() - mDownPosition.x, ev.getY() - mDownPosition.y);
if (mDownDelta.length() > mViewConfig.getScaledTouchSlop() && mMenuVisible) {
- hideMenu();
- mMenuVisible = false;
+ // Restore the input consumer and let that drive the movement of this menu
+ notifyRegisterInputConsumer();
+ cancelDelayedFinish();
}
+ break;
}
return super.dispatchTouchEvent(ev);
}
@@ -219,17 +232,21 @@ public class PipMenuActivity extends Activity {
}
});
mMenuContainerAnimator.start();
+ } else {
+ repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
}
}
private void hideMenu() {
- hideMenu(null /* animationFinishedRunnable */);
+ hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */);
}
- private void hideMenu(final Runnable animationFinishedRunnable) {
+ private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility) {
if (mMenuVisible) {
cancelDelayedFinish();
- notifyMenuVisibility(false);
+ if (notifyMenuVisibility) {
+ notifyMenuVisibility(false);
+ }
mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 0f);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
@@ -253,26 +270,30 @@ public class PipMenuActivity extends Activity {
}
private void updateActionViews() {
+ ViewGroup expandContainer = (ViewGroup) findViewById(R.id.expand_container);
ViewGroup actionsContainer = (ViewGroup) findViewById(R.id.actions_container);
actionsContainer.setOnTouchListener((v, ev) -> {
// Do nothing, prevent click through to parent
return true;
});
+ int actionsContainerHeight = 0;
if (mActions.isEmpty()) {
actionsContainer.setVisibility(View.INVISIBLE);
} else {
actionsContainer.setVisibility(View.VISIBLE);
- ViewGroup actionsGroup = (ViewGroup) findViewById(R.id.actions);
- if (actionsGroup != null) {
- actionsGroup.removeAllViews();
+ if (mActionsGroup != null) {
+ mActionsGroup.removeAllViews();
// Recreate the layout
+ final View decorView = getWindow().getDecorView();
+ final boolean isLandscapePip = decorView.getMeasuredWidth()
+ > decorView.getMeasuredHeight();
final LayoutInflater inflater = LayoutInflater.from(this);
for (int i = 0; i < mActions.size(); i++) {
final RemoteAction action = mActions.get(i);
final ImageView actionView = (ImageView) inflater.inflate(
- R.layout.pip_menu_action, actionsGroup, false);
+ R.layout.pip_menu_action, mActionsGroup, false);
action.getIcon().loadDrawableAsync(this, d -> {
d.setTint(Color.WHITE);
actionView.setImageDrawable(d);
@@ -285,10 +306,27 @@ public class PipMenuActivity extends Activity {
Log.w(TAG, "Failed to send action", e);
}
});
- actionsGroup.addView(actionView);
+ if (isLandscapePip && i > 0) {
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ actionView.getLayoutParams();
+ lp.leftMargin = mBetweenActionPaddingLand;
+ }
+ mActionsGroup.addView(actionView);
}
}
+ actionsContainerHeight = actionsContainer.getLayoutParams().height;
}
+
+ // Update the expand container margin to account for the existence of the action container
+ ((FrameLayout.LayoutParams) expandContainer.getLayoutParams()).bottomMargin =
+ actionsContainerHeight;
+ expandContainer.requestLayout();
+ }
+
+ private void notifyRegisterInputConsumer() {
+ Message m = Message.obtain();
+ m.what = PipMenuActivityController.MESSAGE_REGISTER_INPUT_CONSUMER;
+ sendMessage(m, "Could not notify controller to register input consumer");
}
private void notifyMenuVisibility(boolean visible) {
@@ -300,10 +338,12 @@ public class PipMenuActivity extends Activity {
}
private void expandPip() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
hideMenu(() -> {
sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP,
"Could not notify controller to expand PIP");
- });
+ }, false /* notifyMenuVisibility */);
}
private void minimizePip() {
@@ -312,10 +352,12 @@ public class PipMenuActivity extends Activity {
}
private void dismissPip() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
hideMenu(() -> {
sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP,
"Could not notify controller to dismiss PIP");
- });
+ }, false /* notifyMenuVisibility */);
}
private void notifyActivityCallback(Messenger callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 91115d034671..0b1c3ecc47bd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -57,6 +57,7 @@ public class PipMenuActivityController {
public static final int MESSAGE_MINIMIZE_PIP = 102;
public static final int MESSAGE_DISMISS_PIP = 103;
public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
+ public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
/**
* A listener interface to receive notification on changes in PIP.
@@ -64,8 +65,11 @@ public class PipMenuActivityController {
public interface Listener {
/**
* Called when the PIP menu visibility changes.
+ *
+ * @param menuVisible whether or not the menu is visible
+ * @param resize whether or not to resize the PiP with the visibility change
*/
- void onPipMenuVisibilityChanged(boolean visible);
+ void onPipMenuVisibilityChanged(boolean menuVisible, boolean resize);
/**
* Called when the PIP requested to be expanded.
@@ -85,13 +89,13 @@ public class PipMenuActivityController {
private Context mContext;
private IActivityManager mActivityManager;
- private IWindowManager mWindowManager;
private PipMediaController mMediaController;
+ private InputConsumerController mInputConsumerController;
private ArrayList<Listener> mListeners = new ArrayList<>();
private ParceledListSlice mAppActions;
private ParceledListSlice mMediaActions;
- private boolean mVisible;
+ private boolean mMenuVisible;
private Messenger mToActivityMessenger;
private Messenger mMessenger = new Messenger(new Handler() {
@@ -100,13 +104,14 @@ public class PipMenuActivityController {
switch (msg.what) {
case MESSAGE_MENU_VISIBILITY_CHANGED: {
boolean visible = msg.arg1 > 0;
- onMenuVisibilityChanged(visible);
+ onMenuVisibilityChanged(visible, true /* resize */);
break;
}
case MESSAGE_EXPAND_PIP: {
mListeners.forEach(l -> l.onPipExpand());
- // Preemptively mark the menu as invisible once we expand the PiP
- onMenuVisibilityChanged(false);
+ // Preemptively mark the menu as invisible once we expand the PiP, but don't
+ // resize as we will be animating the stack
+ onMenuVisibilityChanged(false, false /* resize */);
break;
}
case MESSAGE_MINIMIZE_PIP: {
@@ -115,15 +120,20 @@ public class PipMenuActivityController {
}
case MESSAGE_DISMISS_PIP: {
mListeners.forEach(l -> l.onPipDismiss());
- // Preemptively mark the menu as invisible once we dismiss the PiP
- onMenuVisibilityChanged(false);
+ // Preemptively mark the menu as invisible once we dismiss the PiP, but don't
+ // resize as we'll be removing the stack in place
+ onMenuVisibilityChanged(false, false /* resize */);
+ break;
+ }
+ case MESSAGE_REGISTER_INPUT_CONSUMER: {
+ mInputConsumerController.registerInputConsumer();
break;
}
case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
mToActivityMessenger = msg.replyTo;
// Mark the menu as invisible once the activity finishes as well
if (mToActivityMessenger == null) {
- onMenuVisibilityChanged(false);
+ onMenuVisibilityChanged(false, true /* resize */);
}
break;
}
@@ -140,11 +150,19 @@ public class PipMenuActivityController {
};
public PipMenuActivityController(Context context, IActivityManager activityManager,
- IWindowManager windowManager, PipMediaController mediaController) {
+ PipMediaController mediaController, InputConsumerController inputConsumerController) {
mContext = context;
mActivityManager = activityManager;
- mWindowManager = windowManager;
mMediaController = mediaController;
+ mInputConsumerController = inputConsumerController;
+ }
+
+ public void onActivityPinned() {
+ if (!mMenuVisible) {
+ // If the menu is not visible, then re-register the input consumer if it is not already
+ // registered
+ mInputConsumerController.registerInputConsumer();
+ }
}
/**
@@ -192,6 +210,21 @@ public class PipMenuActivityController {
}
/**
+ * Pokes the menu, indicating that the user is interacting with it.
+ */
+ public void pokeMenu() {
+ if (mToActivityMessenger != null) {
+ Message m = Message.obtain();
+ m.what = PipMenuActivity.MESSAGE_POKE_MENU;
+ try {
+ mToActivityMessenger.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not notify poke menu", e);
+ }
+ }
+ }
+
+ /**
* Hides the menu activity.
*/
public void hideMenu() {
@@ -207,6 +240,13 @@ public class PipMenuActivityController {
}
/**
+ * @return whether the menu is currently visible.
+ */
+ public boolean isMenuVisible() {
+ return mMenuVisible;
+ }
+
+ /**
* Sets the menu actions to the actions provided by the current PiP activity.
*/
public void setAppActions(ParceledListSlice appActions) {
@@ -250,9 +290,14 @@ public class PipMenuActivityController {
/**
* Handles changes in menu visibility.
*/
- private void onMenuVisibilityChanged(boolean visible) {
- mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible));
- if (visible != mVisible) {
+ private void onMenuVisibilityChanged(boolean visible, boolean resize) {
+ if (visible) {
+ mInputConsumerController.unregisterInputConsumer();
+ } else {
+ mInputConsumerController.registerInputConsumer();
+ }
+ if (visible != mMenuVisible) {
+ mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible, resize));
if (visible) {
// Once visible, start listening for media action changes. This call will trigger
// the menu actions to be updated again.
@@ -263,13 +308,13 @@ public class PipMenuActivityController {
mMediaController.removeListener(mMediaActionListener);
}
}
- mVisible = visible;
+ mMenuVisible = visible;
}
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
- pw.println(innerPrefix + "mVisible=" + mVisible);
+ pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
pw.println(innerPrefix + "mListeners=" + mListeners.size());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index ed0a37fed52d..20c1136a5998 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -57,10 +57,11 @@ public class PipMotionHelper {
private static final int DEFAULT_MOVE_STACK_DURATION = 225;
private static final int SNAP_STACK_DURATION = 225;
private static final int DISMISS_STACK_DURATION = 375;
- private static final int SHRINK_STACK_FROM_MENU_DURATION = 175;
- private static final int EXPAND_STACK_TO_MENU_DURATION = 175;
- private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 225;
+ private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
+ private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
+ private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 300;
private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+ private static final int IME_SHIFT_DURATION = 300;
// The fraction of the stack width that the user has to drag offscreen to minimize the PiP
private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.2f;
@@ -217,19 +218,12 @@ public class PipMotionHelper {
/**
* Animates the PiP to the minimized state, slightly offscreen.
*/
- Rect animateToClosestMinimizedState(Rect movementBounds,
- final PipMenuActivityController menuController) {
+ Rect animateToClosestMinimizedState(Rect movementBounds) {
cancelAnimations();
Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener);
- mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- menuController.hideMenu();
- }
- });
mBoundsAnimator.start();
}
return toBounds;
@@ -274,9 +268,7 @@ public class PipMotionHelper {
Rect expandedMovementBounds) {
float savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), movementBounds);
mSnapAlgorithm.applySnapFraction(expandedBounds, expandedMovementBounds, savedSnapFraction);
- mBoundsAnimator = createAnimationToBounds(mBounds, expandedBounds,
- EXPAND_STACK_TO_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
- mBoundsAnimator.start();
+ resizeAndAnimatePipUnchecked(expandedBounds, EXPAND_STACK_TO_MENU_DURATION);
return savedSnapFraction;
}
@@ -284,15 +276,25 @@ public class PipMotionHelper {
* Animates the PiP from the expanded state to the normal state after the menu is hidden.
*/
void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction,
- Rect normalMovementBounds) {
- if (savedSnapFraction >= 0f) {
- mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
- mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds,
- SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener);
- mBoundsAnimator.start();
- } else {
- animateToClosestSnapTarget(normalMovementBounds);
+ Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized) {
+ if (savedSnapFraction < 0f) {
+ // If there are no saved snap fractions, then just use the current bounds
+ savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds),
+ currentMovementBounds);
+ }
+ mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
+ if (minimized) {
+ normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds);
}
+ resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION);
+ }
+
+ /**
+ * Animates the PiP to offset it from the IME.
+ */
+ void animateToIMEOffset(Rect toBounds) {
+ cancelAnimations();
+ resizeAndAnimatePipUnchecked(toBounds, IME_SHIFT_DURATION);
}
/**
@@ -317,18 +319,6 @@ public class PipMotionHelper {
}
/**
- * Animates the PiP to some given bounds.
- */
- void animateToBounds(Rect toBounds) {
- cancelAnimations();
- if (!mBounds.equals(toBounds)) {
- mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
- DEFAULT_MOVE_STACK_DURATION, FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
- mBoundsAnimator.start();
- }
- }
-
- /**
* Cancels all existing animations.
*/
void cancelAnimations() {
@@ -365,7 +355,32 @@ public class PipMotionHelper {
mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
mBounds.set(toBounds);
} catch (RemoteException e) {
- Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e);
+ Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e);
+ }
+ });
+ }
+ }
+
+ /**
+ * Directly resizes the PiP to the given {@param bounds}.
+ */
+ private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) {
+ if (!toBounds.equals(mBounds)) {
+ mHandler.post(() -> {
+ try {
+ StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ // In the case where we've already re-expanded or dismissed the PiP, then
+ // just skip the resize
+ return;
+ }
+
+ mActivityManager.resizeStack(PINNED_STACK_ID, toBounds,
+ false /* allowResizeInDockedMode */, true /* preserveWindows */,
+ true /* animate */, duration);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 4100b66b07b6..010522d2818d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,27 +16,24 @@
package com.android.systemui.pip.phone;
-import static android.view.WindowManager.INPUT_CONSUMER_PIP;
-
import android.app.IActivityManager;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Size;
import android.view.IPinnedStackController;
import android.view.IWindowManager;
-import android.view.InputChannel;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.R;
import com.android.systemui.statusbar.FlingAnimationUtils;
import java.io.PrintWriter;
@@ -59,12 +56,10 @@ public class PipTouchHandler {
private final Context mContext;
private final IActivityManager mActivityManager;
- private final IWindowManager mWindowManager;
private final ViewConfiguration mViewConfig;
private final PipMenuListener mMenuListener = new PipMenuListener();
private IPinnedStackController mPinnedStackController;
- private PipInputEventReceiver mInputEventReceiver;
private final PipMenuActivityController mMenuController;
private final PipDismissViewController mDismissViewController;
private final PipSnapAlgorithm mSnapAlgorithm;
@@ -77,6 +72,7 @@ public class PipTouchHandler {
private Rect mNormalMovementBounds = new Rect();
private Rect mExpandedBounds = new Rect();
private Rect mExpandedMovementBounds = new Rect();
+ private int mExpandedShortestEdgeSize;
private Handler mHandler = new Handler();
private Runnable mShowDismissAffordance = new Runnable() {
@@ -89,9 +85,8 @@ public class PipTouchHandler {
};
// Behaviour states
- private boolean mIsTappingThrough;
- private boolean mIsMinimized;
private boolean mIsMenuVisible;
+ private boolean mIsMinimized;
private boolean mIsImeShowing;
private int mImeHeight;
private float mSavedSnapFraction = -1f;
@@ -106,36 +101,12 @@ public class PipTouchHandler {
private final Rect mTmpBounds = new Rect();
/**
- * Input handler used for Pip windows.
- */
- private final class PipInputEventReceiver extends InputEventReceiver {
-
- public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
-
- @Override
- public void onInputEvent(InputEvent event) {
- boolean handled = true;
- try {
- // To be implemented for input handling over Pip windows
- if (event instanceof MotionEvent) {
- MotionEvent ev = (MotionEvent) event;
- handled = handleTouchEvent(ev);
- }
- } finally {
- finishInputEvent(event, handled);
- }
- }
- }
-
- /**
* A listener for the PIP menu activity.
*/
private class PipMenuListener implements PipMenuActivityController.Listener {
@Override
- public void onPipMenuVisibilityChanged(boolean visible) {
- setMenuVisibilityState(visible);
+ public void onPipMenuVisibilityChanged(boolean menuVisible, boolean resize) {
+ setMenuVisibilityState(menuVisible, resize);
}
@Override
@@ -148,7 +119,7 @@ public class PipTouchHandler {
@Override
public void onPipMinimize() {
setMinimizedStateInternal(true);
- mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
+ mMotionHelper.animateToClosestMinimizedState(mMovementBounds);
}
@Override
@@ -159,13 +130,13 @@ public class PipTouchHandler {
}
}
- public PipTouchHandler(Context context, PipMenuActivityController menuController,
- IActivityManager activityManager, IWindowManager windowManager) {
+ public PipTouchHandler(Context context, IActivityManager activityManager,
+ PipMenuActivityController menuController,
+ InputConsumerController inputConsumerController) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
- mWindowManager = windowManager;
mViewConfig = ViewConfiguration.get(context);
mMenuController = menuController;
mMenuController.addListener(mMenuListener);
@@ -178,7 +149,11 @@ public class PipTouchHandler {
};
mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
mFlingAnimationUtils);
- registerInputConsumer();
+ mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize(
+ R.dimen.pip_expanded_shortest_edge_size);
+
+ // Register the listener for input consumer touch events
+ inputConsumerController.setTouchListener(this::handleTouchEvent);
}
public void setTouchEnabled(boolean enabled) {
@@ -187,9 +162,8 @@ public class PipTouchHandler {
public void onActivityPinned() {
// Reset some states once we are pinned
- if (mIsTappingThrough) {
- mIsTappingThrough = false;
- registerInputConsumer();
+ if (mIsMenuVisible) {
+ mIsMenuVisible = false;
}
if (mIsMinimized) {
setMinimizedStateInternal(false);
@@ -206,15 +180,21 @@ public class PipTouchHandler {
mImeHeight = imeHeight;
}
- public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+ public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds,
boolean fromImeAdjustement) {
// Re-calculate the expanded bounds
mNormalBounds = normalBounds;
Rect normalMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
mIsImeShowing ? mImeHeight : 0);
- // TODO: Figure out the expanded size policy
- mExpandedBounds = new Rect(normalBounds);
+
+ // Calculate the expanded size
+ float aspectRatio = (float) normalBounds.width() / normalBounds.height();
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
+ mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
+ mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
Rect expandedMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
mIsImeShowing ? mImeHeight : 0);
@@ -227,7 +207,7 @@ public class PipTouchHandler {
// Defer the update of the current movement bounds until after the user finishes
// touching the screen
} else {
- final Rect bounds = new Rect(mMotionHelper.getBounds());
+ final Rect bounds = new Rect(animatingBounds);
final Rect toMovementBounds = mIsMenuVisible
? expandedMovementBounds
: normalMovementBounds;
@@ -247,7 +227,7 @@ public class PipTouchHandler {
bounds.offsetTo(bounds.left, toMovementBounds.bottom);
}
}
- mMotionHelper.animateToBounds(bounds);
+ mMotionHelper.animateToIMEOffset(bounds);
}
}
@@ -255,7 +235,7 @@ public class PipTouchHandler {
// above
mNormalMovementBounds = normalMovementBounds;
mExpandedMovementBounds = expandedMovementBounds;
- updateMovementBounds();
+ updateMovementBounds(mIsMenuVisible);
}
private boolean handleTouchEvent(MotionEvent ev) {
@@ -287,7 +267,7 @@ public class PipTouchHandler {
case MotionEvent.ACTION_UP: {
// Update the movement bounds again if the state has changed since the user started
// dragging (ie. when the IME shows)
- updateMovementBounds();
+ updateMovementBounds(mIsMenuVisible);
for (PipTouchGesture gesture : mGestures) {
if (gesture.onUp(mTouchState)) {
@@ -302,38 +282,7 @@ public class PipTouchHandler {
break;
}
}
- return !mIsTappingThrough;
- }
-
- /**
- * Registers the input consumer.
- */
- private void registerInputConsumer() {
- if (mInputEventReceiver == null) {
- final InputChannel inputChannel = new InputChannel();
- try {
- mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
- mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to create PIP input consumer", e);
- }
- mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper());
- }
- }
-
- /**
- * Unregisters the input consumer.
- */
- private void unregisterInputConsumer() {
- if (mInputEventReceiver != null) {
- try {
- mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to destroy PIP input consumer", e);
- }
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
+ return !mIsMenuVisible;
}
/**
@@ -379,34 +328,30 @@ public class PipTouchHandler {
/**
* Sets the menu visibility.
*/
- void setMenuVisibilityState(boolean isMenuVisible) {
- if (!isMenuVisible) {
- mIsTappingThrough = false;
- registerInputConsumer();
- } else {
- unregisterInputConsumer();
- }
- MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
- isMenuVisible);
-
- if (isMenuVisible != mIsMenuVisible) {
- if (isMenuVisible) {
- // Save the current snap fraction and if we do not drag or move the PiP, then
- // we store back to this snap fraction. Otherwise, we'll reset the snap
- // fraction and snap to the closest edge
- Rect expandedBounds = new Rect(mExpandedBounds);
+ void setMenuVisibilityState(boolean menuVisible, boolean resize) {
+ if (menuVisible) {
+ // Save the current snap fraction and if we do not drag or move the PiP, then
+ // we store back to this snap fraction. Otherwise, we'll reset the snap
+ // fraction and snap to the closest edge
+ Rect expandedBounds = new Rect(mExpandedBounds);
+ if (resize) {
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mMovementBounds, mExpandedMovementBounds);
- } else {
- // Try and restore the PiP to the closest edge, using the saved snap fraction
- // if possible
+ }
+ } else {
+ // Try and restore the PiP to the closest edge, using the saved snap fraction
+ // if possible
+ if (resize) {
Rect normalBounds = new Rect(mNormalBounds);
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
- mNormalMovementBounds);
+ mNormalMovementBounds, mMovementBounds, mIsMinimized);
}
- mIsMenuVisible = isMenuVisible;
- updateMovementBounds();
+ mSavedSnapFraction = -1f;
}
+ mIsMenuVisible = menuVisible;
+ updateMovementBounds(menuVisible);
+ MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
+ menuVisible);
}
/**
@@ -427,6 +372,12 @@ public class PipTouchHandler {
return;
}
+ // If the menu is still visible, and we aren't minimized, then just poke the menu
+ // so that it will timeout after the user stops touching it
+ if (mMenuController.isMenuVisible() && !mIsMinimized) {
+ mMenuController.pokeMenu();
+ }
+
if (ENABLE_DRAG_TO_DISMISS) {
mDismissViewController.createDismissTarget();
mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
@@ -495,21 +446,35 @@ public class PipTouchHandler {
} finally {
mDismissViewController.destroyDismissTarget();
}
+
if (touchState.isDragging()) {
PointF vel = mTouchState.getVelocity();
if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
|| isHorizontalFlingTowardsCurrentEdge(vel))) {
// Pip should be minimized
setMinimizedStateInternal(true);
- mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController);
+ if (mMenuController.isMenuVisible()) {
+ // If the user dragged the expanded PiP to the edge, then hiding the menu
+ // will trigger the PiP to be scaled back to the normal size with the
+ // minimize offset adjusted
+ mMenuController.hideMenu();
+ } else {
+ mMotionHelper.animateToClosestMinimizedState(mMovementBounds);
+ }
return true;
}
if (mIsMinimized) {
- // If we're dragging and it wasn't a minimize gesture
- // then we shouldn't be minimized.
+ // If we're dragging and it wasn't a minimize gesture then we shouldn't be
+ // minimized.
setMinimizedStateInternal(false);
}
+ // If the menu is still visible, and we aren't minimized, then just poke the menu
+ // so that it will timeout after the user stops touching it
+ if (mMenuController.isMenuVisible()) {
+ mMenuController.showMenu();
+ }
+
final float velocity = PointF.length(vel.x, vel.y);
if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds);
@@ -520,9 +485,8 @@ public class PipTouchHandler {
// This was a tap, so no longer minimized
mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
setMinimizedStateInternal(false);
- } else if (!mIsTappingThrough) {
+ } else if (!mIsMenuVisible) {
mMenuController.showMenu();
- mIsTappingThrough = true;
} else {
mMotionHelper.expandPip();
}
@@ -559,8 +523,8 @@ public class PipTouchHandler {
/**
* Updates the current movement bounds based on whether the menu is currently visible.
*/
- private void updateMovementBounds() {
- mMovementBounds = mIsMenuVisible
+ private void updateMovementBounds(boolean isExpanded) {
+ mMovementBounds = isExpanded
? mExpandedMovementBounds
: mNormalMovementBounds;
}
@@ -573,9 +537,8 @@ public class PipTouchHandler {
pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds);
pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds);
pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds);
- pw.println(innerPrefix + "mIsTappingThrough=" + mIsTappingThrough);
- pw.println(innerPrefix + "mIsMinimized=" + mIsMinimized);
pw.println(innerPrefix + "mIsMenuVisible=" + mIsMenuVisible);
+ pw.println(innerPrefix + "mIsMinimized=" + mIsMinimized);
pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index d506669f74a8..9a8974d18905 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -197,7 +197,7 @@ public class PipManager implements BasePipManager {
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
- boolean fromImeAdjustement) {
+ Rect animatingBounds, boolean fromImeAdjustement) {
mHandler.post(() -> {
mDefaultPipBounds.set(normalBounds);
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 602c3dfde73e..fc3bb43e4fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -927,12 +927,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (areGutsExposed()) {
return false;
}
- if (mIsSummaryWithChildren) {
- return true;
- }
- NotificationContentView showingLayout = getShowingLayout();
- NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
- return notificationHeader != null;
+ return getVisibleNotificationHeader() != null;
}
/**
@@ -1720,6 +1715,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public boolean isContentExpandable() {
+ if (mIsSummaryWithChildren && !mShowingPublic) {
+ return true;
+ }
NotificationContentView showingLayout = getShowingLayout();
return showingLayout.isContentExpandable();
}
@@ -1987,6 +1985,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (canViewBeDismissed()) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
}
+ boolean expandable = mShowingPublic;
+ boolean isExpanded = false;
+ if (!expandable) {
+ if (mIsSummaryWithChildren) {
+ expandable = true;
+ if (!mIsLowPriority || isExpanded()) {
+ isExpanded = isGroupExpanded();
+ }
+ } else {
+ expandable = mPrivateLayout.isContentExpandable();
+ isExpanded = isExpanded();
+ }
+ }
+ if (expandable) {
+ if (isExpanded) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ }
+ }
}
@Override
@@ -1999,6 +2017,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
NotificationStackScrollLayout.performDismiss(this, mGroupManager,
true /* fromAccessibility */);
return true;
+ case AccessibilityNodeInfo.ACTION_COLLAPSE:
+ case AccessibilityNodeInfo.ACTION_EXPAND:
+ mExpandClickListener.onClick(this);
+ return true;
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 74e65fbd2432..8f160dc0384e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -131,6 +131,7 @@ public class NotificationContentView extends FrameLayout {
private boolean mIconsVisible;
private int mClipBottomAmount;
private boolean mIsLowPriority;
+ private boolean mIsContentExpandable;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -949,7 +950,7 @@ public class NotificationContentView extends FrameLayout {
}
public boolean isContentExpandable() {
- return mExpandedChild != null;
+ return mIsContentExpandable;
}
public void setDark(boolean dark, boolean fade, long delay) {
@@ -1198,10 +1199,10 @@ public class NotificationContentView extends FrameLayout {
if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
|| mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
- if (mExpandedChild.getHeight() == mContractedChild.getHeight()) {
+ if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
expandable = false;
}
- } else if (mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) {
+ } else if (mExpandedChild.getHeight() <= mHeadsUpChild.getHeight()) {
expandable = false;
}
}
@@ -1214,6 +1215,7 @@ public class NotificationContentView extends FrameLayout {
if (mHeadsUpChild != null) {
mHeadsUpWrapper.updateExpandability(expandable, mExpandClickListener);
}
+ mIsContentExpandable = expandable;
}
public NotificationHeaderView getNotificationHeader() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 4a2ec88c7518..7b2e9979fb33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
-import android.os.Build;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
@@ -25,6 +24,7 @@ import android.text.TextUtils;
import android.util.MathUtils;
import android.util.SparseBooleanArray;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.R;
import java.io.PrintWriter;
@@ -32,14 +32,15 @@ import java.io.PrintWriter;
public class DozeParameters {
private static final int MAX_DURATION = 60 * 1000;
public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
- public static final boolean ALWAYS_ON_AVAILABLE = Build.IS_DEBUGGABLE;
private final Context mContext;
+ private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
public DozeParameters(Context context) {
mContext = context;
+ mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
}
public void dump(PrintWriter pw) {
@@ -58,8 +59,7 @@ public class DozeParameters {
pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
dumpPickupSubtypePerformsProxCheck());
- if (ALWAYS_ON_AVAILABLE) {
- pw.print(" getAlwaysOn(): "); pw.println(getAlwaysOn());
+ if (mAmbientDisplayConfiguration.alwaysOnAvailable()) {
pw.print(" getSensorsWakeUpFully(): "); pw.println(getSensorsWakeUpFully());
}
}
@@ -119,13 +119,11 @@ public class DozeParameters {
}
public boolean getAlwaysOn() {
- return ALWAYS_ON_AVAILABLE
- && Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.DOZE_ALWAYS_ON, 0, UserHandle.USER_CURRENT) != 0;
+ return mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
}
public boolean getSensorsWakeUpFully() {
- return ALWAYS_ON_AVAILABLE
+ return mAmbientDisplayConfiguration.alwaysOnAvailable()
&& Settings.Secure.getIntForUser(mContext.getContentResolver(),
DOZE_SENSORS_WAKE_UP_FULLY, 1, UserHandle.USER_CURRENT) != 0;
}
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 19be586710ce..005b701c0d52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -715,6 +715,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private NotificationIconAreaController mNotificationIconAreaController;
private ConfigurationListener mConfigurationListener;
private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
+ private boolean mReinflateNotificationsOnUserSwitched;
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
final int N = array.size();
@@ -1274,16 +1275,10 @@ public class StatusBar extends SystemUI implements DemoMode,
protected void onDensityOrFontScaleChanged() {
// start old BaseStatusBar.onDensityOrFontScaleChanged().
- ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
- for (int i = 0; i < activeNotifications.size(); i++) {
- Entry entry = activeNotifications.get(i);
- boolean exposedGuts = mNotificationGutsExposed != null
- && entry.row.getGuts() == mNotificationGutsExposed;
- entry.row.onDensityOrFontScaleChanged();
- if (exposedGuts) {
- mNotificationGutsExposed = entry.row.getGuts();
- bindGuts(entry.row, mGutsMenuItem);
- }
+ if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+ updateNotificationsOnDensityOrFontScaleChanged();
+ } else {
+ mReinflateNotificationsOnUserSwitched = true;
}
// end old BaseStatusBar.onDensityOrFontScaleChanged().
mScrimController.onDensityOrFontScaleChanged();
@@ -1308,6 +1303,20 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
+ private void updateNotificationsOnDensityOrFontScaleChanged() {
+ ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
+ for (int i = 0; i < activeNotifications.size(); i++) {
+ Entry entry = activeNotifications.get(i);
+ boolean exposedGuts = mNotificationGutsExposed != null
+ && entry.row.getGuts() == mNotificationGutsExposed;
+ entry.row.onDensityOrFontScaleChanged();
+ if (exposedGuts) {
+ mNotificationGutsExposed = entry.row.getGuts();
+ bindGuts(entry.row, mGutsMenuItem);
+ }
+ }
+ }
+
private void inflateSignalClusters() {
reinflateSignalCluster(mKeyguardStatusBar);
}
@@ -3598,7 +3607,12 @@ public class StatusBar extends SystemUI implements DemoMode,
if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
animateCollapsePanels();
updatePublicMode();
- updateNotifications();
+ mNotificationData.filterAndSort();
+ if (mReinflateNotificationsOnUserSwitched) {
+ updateNotificationsOnDensityOrFontScaleChanged();
+ mReinflateNotificationsOnUserSwitched = false;
+ }
+ updateNotificationShade();
clearCurrentMediaNotification();
setLockscreenUser(newUserId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 209b439e876c..e7bce708e48f 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -26,11 +26,11 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.plugins.PluginPrefs;
-import com.android.systemui.statusbar.phone.DozeParameters;
public class TunerFragment extends PreferenceFragment {
@@ -65,7 +65,7 @@ public class TunerFragment extends PreferenceFragment {
if (!PluginPrefs.hasPlugins(getContext())) {
getPreferenceScreen().removePreference(findPreference(KEY_PLUGINS));
}
- if (!DozeParameters.ALWAYS_ON_AVAILABLE) {
+ if (!alwaysOnAvailable()) {
getPreferenceScreen().removePreference(findPreference(KEY_DOZE));
}
@@ -77,6 +77,10 @@ public class TunerFragment extends PreferenceFragment {
}
}
+ private boolean alwaysOnAvailable() {
+ return new AmbientDisplayConfiguration(getContext()).alwaysOnAvailable();
+ }
+
@Override
public void onResume() {
super.onResume();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 32afee9744d5..267580e5b35b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -28,8 +28,9 @@ import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -42,7 +43,7 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Display;
-import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import org.junit.Before;
import org.junit.Test;
@@ -56,17 +57,17 @@ public class DozeMachineTest {
private DozeServiceFake mServiceFake;
private WakeLockFake mWakeLockFake;
- private DozeParameters mParamsMock;
+ private AmbientDisplayConfiguration mConfigMock;
private DozeMachine.Part mPartMock;
@Before
public void setUp() {
mServiceFake = new DozeServiceFake();
mWakeLockFake = new WakeLockFake();
- mParamsMock = mock(DozeParameters.class);
+ mConfigMock = mock(AmbientDisplayConfiguration.class);
mPartMock = mock(DozeMachine.Part.class);
- mMachine = new DozeMachine(mServiceFake, mParamsMock, mWakeLockFake);
+ mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake);
mMachine.setParts(new DozeMachine.Part[]{mPartMock});
}
@@ -82,7 +83,7 @@ public class DozeMachineTest {
@Test
@UiThreadTest
public void testInitialize_goesToDoze() {
- when(mParamsMock.getAlwaysOn()).thenReturn(false);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
mMachine.requestState(INITIALIZED);
@@ -93,7 +94,7 @@ public class DozeMachineTest {
@Test
@UiThreadTest
public void testInitialize_goesToAod() {
- when(mParamsMock.getAlwaysOn()).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
mMachine.requestState(INITIALIZED);
@@ -104,7 +105,7 @@ public class DozeMachineTest {
@Test
@UiThreadTest
public void testPulseDone_goesToDoze() {
- when(mParamsMock.getAlwaysOn()).thenReturn(false);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
mMachine.requestState(INITIALIZED);
mMachine.requestState(DOZE_REQUEST_PULSE);
mMachine.requestState(DOZE_PULSING);
@@ -118,7 +119,7 @@ public class DozeMachineTest {
@Test
@UiThreadTest
public void testPulseDone_goesToAoD() {
- when(mParamsMock.getAlwaysOn()).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
mMachine.requestState(INITIALIZED);
mMachine.requestState(DOZE_REQUEST_PULSE);
mMachine.requestState(DOZE_PULSING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
new file mode 100644
index 000000000000..bf741ec41ac7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationInflater;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExpandableNotificationRowTest {
+
+ private Context mContext;
+ private ExpandableNotificationRow mRow;
+ private NotificationGroupManager mGroupManager = new NotificationGroupManager();
+ private int mId;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mRow = createNotification();
+ }
+
+ private ExpandableNotificationRow createNotification() {
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
+ R.layout.status_bar_notification_row,
+ null, false);
+ row.setGroupManager(mGroupManager);
+ Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
+ R.drawable.ic_person)
+ .setCustomContentView(new RemoteViews(mContext.getPackageName(),
+ R.layout.custom_view_dark))
+ .build();
+ Notification notification = new Notification.Builder(mContext).setSmallIcon(
+ R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .setPublicVersion(publicVersion)
+ .build();
+ UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+ StatusBarNotification sbn = new StatusBarNotification("com.android.systemui",
+ "com.android.systemui", mId++, null, 1000,
+ 2000, notification, mUser, null, System.currentTimeMillis());
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ entry.row = row;
+ try {
+ entry.createIcons(mContext, sbn);
+ row.updateNotification(entry);
+ } catch (InflationException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ return row;
+ }
+
+ @Test
+ public void testGroupSummaryNotShowingIconWhenPublic() {
+ mRow.setSensitive(true, true);
+ mRow.addChildNotification(createNotification());
+ mRow.addChildNotification(createNotification());
+ mRow.setHideSensitive(true, false, 0, 0);
+ Assert.assertTrue(mRow.isSummaryWithChildren());
+ Assert.assertFalse(mRow.isShowingIcon());
+ }
+
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2b219e637aed..44de0bdd9409 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3486,6 +3486,37 @@ message MetricsEvent {
// ACTION: Settings > Battery > Menu > Apps Toggle
ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852;
+ // ACTION: Settings > Any preference is changed
+ ACTION_SETTINGS_PREFERENCE_CHANGE = 853;
+
+ // FIELD: The name of preference when it is changed in Settings
+ FIELD_SETTINGS_PREFERENCE_CHANGE_NAME = 854;
+
+ // FIELD: The new value of preference when it is changed in Settings
+ FIELD_SETTINGS_PREFERENCE_CHANGE_VALUE = 855;
+
+ // OPEN: Notification channel created. CLOSE: Notification channel deleted. UPDATE: notification
+ // channel updated
+ // PACKAGE: the package the channel belongs too
+ // CATEGORY: NOTIFICATION
+ // OS: O
+ ACTION_NOTIFICATION_CHANNEL = 856;
+
+ // Tagged data for notification channel. String.
+ FIELD_NOTIFICATION_CHANNEL_ID = 857;
+
+ // Tagged data for notification channel. int.
+ FIELD_NOTIFICATION_CHANNEL_IMPORTANCE = 858;
+
+ // OPEN: Notification channel group created.
+ // PACKAGE: the package the group belongs to
+ // CATEGORY: NOTIFICATION
+ // OS: O
+ ACTION_NOTIFICATION_CHANNEL_GROUP = 859;
+
+ // Tagged data for notification channel group. String.
+ FIELD_NOTIFICATION_CHANNEL_GROUP_ID = 860;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 9d2f75080bb6..667bf71363da 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -1071,7 +1071,6 @@ public class Element extends BaseObj {
mSize += mElements[ct].mSize * mArraySizes[ct];
}
updateVisibleSubElements();
- guard.open("destroy");
}
Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -1091,7 +1090,6 @@ public class Element extends BaseObj {
mKind = dk;
mNormalized = norm;
mVectorSize = size;
- guard.open("destroy");
}
Element(long id, RenderScript rs) {
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 9252898781f4..dc2378596d00 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -227,7 +227,6 @@ public class Type extends BaseObj {
Type(long id, RenderScript rs) {
super(id, rs);
- guard.open("destroy");
}
@Override
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 82d86ffd95cb..df6148e653d7 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -641,6 +641,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (appCount == 0 && mEnable) {
disableBleScanMode();
}
+ if (appCount == 0 && !mEnableExternal) {
+ sendBrEdrDownCallback();
+ }
return appCount;
}
@@ -696,7 +699,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return;
}
- if (isBleAppPresent() == false) {
+ if (isBleAppPresent()) {
+ // Need to stay at BLE ON. Disconnect all Gatt connections
+ try {
+ mBluetoothGatt.unregAll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to disconnect all apps.", e);
+ }
+ } else {
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) mBluetooth.onBrEdrDown();
@@ -705,14 +715,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} finally {
mBluetoothLock.readLock().unlock();
}
- } else {
- // Need to stay at BLE ON. Disconnect all Gatt connections
- try {
- mBluetoothGatt.unregAll();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect all apps.", e);
- }
}
+
}
public boolean enableNoAutoConnect(String packageName)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0bc9d19ab1ec..16ed2768de89 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -395,16 +395,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
- /**
- * Indicates a caller has requested to have its callback invoked with
- * the latest LinkProperties or NetworkCapabilities.
- *
- * arg1 = UID of caller
- * obj = NetworkRequest
- */
- private static final int EVENT_REQUEST_LINKPROPERTIES = 32;
- private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
-
/** Handler thread used for both of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -2565,34 +2555,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nri;
}
- private void handleRequestCallbackUpdate(NetworkRequest request, int callingUid,
- String description, int callbackType) {
- final NetworkRequestInfo nri = getNriForAppRequest(request, callingUid, description);
- if (nri == null) return;
-
- final NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
- // The network that is satisfying this request may have changed since
- // the application requested the update.
- //
- // - If the request is no longer satisfied, don't send any updates.
- // - If the request is satisfied by a different network, it is the
- // caller's responsibility to check that the Network object in the
- // callback matches the network that was returned in the last
- // onAvailable() callback for this request.
- if (nai == null) return;
- callCallbackForRequest(nri, nai, callbackType, 0);
- }
-
- private void handleRequestLinkProperties(NetworkRequest request, int callingUid) {
- handleRequestCallbackUpdate(request, callingUid,
- "request LinkProperties", ConnectivityManager.CALLBACK_IP_CHANGED);
- }
-
- private void handleRequestNetworkCapabilities(NetworkRequest request, int callingUid) {
- handleRequestCallbackUpdate(request, callingUid,
- "request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
nri.request.requestId) == null) {
@@ -2986,12 +2948,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
handleMobileDataAlwaysOn();
break;
}
- case EVENT_REQUEST_LINKPROPERTIES:
- handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
- break;
- case EVENT_REQUEST_NETCAPABILITIES:
- handleRequestNetworkCapabilities((NetworkRequest) msg.obj, msg.arg1);
- break;
// Sent by KeepaliveTracker to process an app request on the state machine thread.
case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
mKeepaliveTracker.handleStartKeepalive(msg);
@@ -4352,22 +4308,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public void requestLinkProperties(NetworkRequest networkRequest) {
- ensureNetworkRequestHasType(networkRequest);
- if (networkRequest.type == NetworkRequest.Type.LISTEN) return;
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_REQUEST_LINKPROPERTIES, getCallingUid(), 0, networkRequest));
- }
-
- @Override
- public void requestNetworkCapabilities(NetworkRequest networkRequest) {
- ensureNetworkRequestHasType(networkRequest);
- if (networkRequest.type == NetworkRequest.Type.LISTEN) return;
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_REQUEST_NETCAPABILITIES, getCallingUid(), 0, networkRequest));
- }
-
- @Override
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
mHandler.sendMessage(mHandler.obtainMessage(
@@ -4879,7 +4819,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!nr.isListen()) continue;
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
nai.addRequest(nr);
- notifyNetworkCallback(nai, nri);
+ notifyNetworkAvailable(nai, nri);
}
}
}
@@ -5061,7 +5001,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// do this after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
- for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
+ for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
// Linger any networks that are no longer needed. This should be done after sending the
// available callback for newNetwork.
@@ -5224,7 +5164,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
- NetworkInfo.State state = newInfo.getState();
+ final NetworkInfo.State state = newInfo.getState();
NetworkInfo oldInfo = null;
final int oldScore = networkAgent.getCurrentScore();
synchronized (networkAgent) {
@@ -5351,15 +5291,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
sendUpdatedScoreToFactories(nai);
}
- // notify only this one new request of the current state
- protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) {
- int notifyType = ConnectivityManager.CALLBACK_AVAILABLE;
+ // Notify only this one new request of the current state. Transfer all the
+ // current state by calling NetworkCapabilities and LinkProperties callbacks
+ // so that callers can be guaranteed to have as close to atomicity in state
+ // transfer as can be supported by this current API.
+ protected void notifyNetworkAvailable(NetworkAgentInfo nai, NetworkRequestInfo nri) {
mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri);
- if (nri.mPendingIntent == null) {
- callCallbackForRequest(nri, nai, notifyType, 0);
- } else {
- sendPendingIntentForRequest(nri, nai, notifyType);
+ if (nri.mPendingIntent != null) {
+ sendPendingIntentForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE);
+ // Attempt no subsequent state pushes where intents are involved.
+ return;
+ }
+
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);
+ // Whether a network is currently suspended is also an important
+ // element of state to be transferred (it would not otherwise be
+ // delivered by any currently available mechanism).
+ if (nai.networkInfo.getState() == NetworkInfo.State.SUSPENDED) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_SUSPENDED, 0);
}
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_CAP_CHANGED, 0);
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_IP_CHANGED, 0);
}
private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 0a9610f36abb..d9073f6cbf55 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -2198,18 +2198,26 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
// Managed profile should have escrow enabled
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
+ Slog.i(TAG, "Managed profile can have escrow token");
return;
}
DevicePolicyManager dpm = (DevicePolicyManager)
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
// Devices with Device Owner should have escrow enabled on all users.
if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
+ Slog.i(TAG, "Corp-owned device can have escrow token");
+ return;
+ }
+ // We could also have a profile owner on the given (non-managed) user for unicorn cases
+ if (dpm.getProfileOwnerAsUser(userId) != null) {
+ Slog.i(TAG, "User with profile owner can have escrow token");
return;
}
// If the device is yet to be provisioned (still in SUW), there is still
// a chance that Device Owner will be set on the device later, so postpone
// disabling escrow token for now.
if (!dpm.isDeviceProvisioned()) {
+ Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
return;
}
// Disable escrow token permanently on all other device/user types.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6e138a161e1c..bd7086165a07 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2770,7 +2770,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// while pausing because that changes the focused stack and may prevent the new
// starting activity from resuming.
if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE
- && !r.supportsPictureInPictureWhilePausing) {
+ && (r.state == RESUMED || !r.supportsPictureInPictureWhilePausing)) {
// Move the home stack forward if the task we just moved to the pinned stack
// was launched from home so home should be visible behind it.
moveHomeStackToFront(reason);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 39e3758393df..60357c2befb9 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -77,6 +77,7 @@ import com.android.internal.util.StateMachine;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
+import com.android.server.connectivity.tethering.OffloadController;
import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -146,6 +147,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
.getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
private final StateMachine mTetherMasterSM;
+ private final OffloadController mOffloadController;
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
private String mCurrentUpstreamIface;
@@ -176,6 +178,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
+ mOffloadController = new OffloadController(mTetherMasterSM.getHandler());
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
@@ -1205,6 +1208,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
protected void handleNewUpstreamNetworkState(NetworkState ns) {
mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
+ mOffloadController.setUpstreamLinkProperties(
+ (ns != null) ? ns.linkProperties : null);
}
}
@@ -1361,12 +1366,14 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
class TetherModeAliveState extends TetherMasterUtilState {
final SimChangeListener simChange = new SimChangeListener(mContext);
boolean mTryCell = true;
+
@Override
public void enter() {
// TODO: examine if we should check the return value.
turnOnMasterTetherSettings(); // may transition us out
simChange.startListening();
mUpstreamNetworkMonitor.start();
+ mOffloadController.start();
// Better try something first pass or crazy tests cases will fail.
chooseUpstreamType(true);
@@ -1375,6 +1382,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
@Override
public void exit() {
+ mOffloadController.stop();
unrequestUpstreamMobileConnection();
mUpstreamNetworkMonitor.stop();
simChange.stopListening();
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
new file mode 100644
index 000000000000..220e7514facc
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.net.LinkProperties;
+import android.os.Handler;
+import android.util.Log;
+
+/**
+ * A wrapper around hardware offload interface.
+ *
+ * @hide
+ */
+public class OffloadController {
+ private static final String TAG = OffloadController.class.getSimpleName();
+
+ private final Handler mHandler;
+ private LinkProperties mUpstreamLinkProperties;
+
+ public OffloadController(Handler h) {
+ mHandler = h;
+ }
+
+ public void start() {
+ // TODO: initOffload() and configure callbacks to be handled on our
+ // preferred Handler.
+ Log.d(TAG, "tethering offload not supported");
+ }
+
+ public void stop() {
+ // TODO: stopOffload().
+ mUpstreamLinkProperties = null;
+ }
+
+ public void setUpstreamLinkProperties(LinkProperties lp) {
+ // TODO: setUpstreamParameters().
+ mUpstreamLinkProperties = lp;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 6106093e4008..62099293b31c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -186,6 +186,7 @@ public class UpstreamNetworkMonitor {
switch (callbackType) {
case CALLBACK_LISTEN_ALL:
break;
+
case CALLBACK_TRACK_DEFAULT:
if (mDefaultNetworkCallback == null) {
// The callback was unregistered in the interval between
@@ -198,11 +199,9 @@ public class UpstreamNetworkMonitor {
// These request*() calls can be deleted post oag/339444.
return;
}
-
- cm().requestNetworkCapabilities(mDefaultNetworkCallback);
- cm().requestLinkProperties(mDefaultNetworkCallback);
mCurrentDefault = network;
break;
+
case CALLBACK_MOBILE_REQUEST:
if (mMobileNetworkCallback == null) {
// The callback was unregistered in the interval between
@@ -211,13 +210,8 @@ public class UpstreamNetworkMonitor {
//
// Clean-up of this network entry is deferred to the
// handling of onLost() by other callbacks.
- //
- // These request*() calls can be deleted post oag/339444.
return;
}
-
- cm().requestNetworkCapabilities(mMobileNetworkCallback);
- cm().requestLinkProperties(mMobileNetworkCallback);
break;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0e767daf76c8..be8aaf02db41 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2792,6 +2792,7 @@ public class NotificationManagerService extends SystemService {
dump.put("bans", mRankingHelper.dumpBansJson(filter));
dump.put("ranking", mRankingHelper.dumpJson(filter));
dump.put("stats", mUsageStats.dumpJson(filter));
+ dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
} catch (JSONException e) {
e.printStackTrace();
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 3016b17db7b9..d751a2258dc6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -778,9 +778,9 @@ public final class NotificationRecord {
.addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag());
}
return mLogMaker
- .setCategory(MetricsEvent.VIEW_UNKNOWN)
- .setType(MetricsEvent.TYPE_UNKNOWN)
- .setSubtype(0)
+ .clearCategory()
+ .clearType()
+ .clearSubtype()
.clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index bb0742adf465..4cabe4e23ba4 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,6 +19,8 @@ import static android.app.NotificationManager.IMPORTANCE_NONE;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;
import android.app.Notification;
@@ -30,6 +32,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
+import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@@ -485,6 +488,12 @@ public class RankingHelper implements RankingConfig {
if (r == null) {
throw new IllegalArgumentException("Invalid package");
}
+ LogMaker lm = new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
+ .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
+ group.getId())
+ .setPackageName(pkg);
+ MetricsLogger.action(lm);
r.groups.put(group.getId(), group);
updateConfig();
}
@@ -507,14 +516,20 @@ public class RankingHelper implements RankingConfig {
if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
}
+ if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
+ throw new IllegalArgumentException("Reserved id");
+ }
NotificationChannel existing = r.channels.get(channel.getId());
// Keep existing settings
if (existing != null) {
if (existing.isDeleted()) {
existing.setDeleted(false);
- updateConfig();
}
+
+ MetricsLogger.action(getChannelLog(channel, pkg));
+
+ updateConfig();
return;
}
if (channel.getImportance() < NotificationManager.IMPORTANCE_NONE
@@ -538,6 +553,8 @@ public class RankingHelper implements RankingConfig {
Notification.AUDIO_ATTRIBUTES_DEFAULT);
}
r.channels.put(channel.getId(), channel);
+ MetricsLogger.action(getChannelLog(channel, pkg).setType(
+ MetricsProto.MetricsEvent.TYPE_OPEN));
updateConfig();
}
@@ -565,6 +582,8 @@ public class RankingHelper implements RankingConfig {
updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
}
r.channels.put(updatedChannel.getId(), updatedChannel);
+
+ MetricsLogger.action(getChannelLog(updatedChannel, pkg));
updateConfig();
}
@@ -612,6 +631,7 @@ public class RankingHelper implements RankingConfig {
}
// Assistant cannot change the group
+ MetricsLogger.action(getChannelLog(channel, pkg));
r.channels.put(channel.getId(), channel);
updateConfig();
}
@@ -661,6 +681,9 @@ public class RankingHelper implements RankingConfig {
if (channel != null) {
channel.setDeleted(true);
}
+ LogMaker lm = getChannelLog(channel, pkg);
+ lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ MetricsLogger.action(lm);
}
@Override
@@ -932,6 +955,49 @@ public class RankingHelper implements RankingConfig {
return packageBans;
}
+ /**
+ * Dump only the channel information as structured JSON for the stats collector.
+ *
+ * This is intentionally redundant with {#link dumpJson} because the old
+ * scraper will expect this format.
+ *
+ * @param filter
+ * @return
+ */
+ public JSONArray dumpChannelsJson(NotificationManagerService.DumpFilter filter) {
+ JSONArray channels = new JSONArray();
+ Map<String, Integer> packageChannels = getPackageChannels();
+ for(Entry<String, Integer> channelCount : packageChannels.entrySet()) {
+ final String packageName = channelCount.getKey();
+ if (filter == null || filter.matches(packageName)) {
+ JSONObject channelCountJson = new JSONObject();
+ try {
+ channelCountJson.put("packageName", packageName);
+ channelCountJson.put("channelCount", channelCount.getValue());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ channels.put(channelCountJson);
+ }
+ }
+ return channels;
+ }
+
+ private Map<String, Integer> getPackageChannels() {
+ ArrayMap<String, Integer> packageChannels = new ArrayMap<>();
+ for (int i = 0; i < mRecords.size(); i++) {
+ final Record r = mRecords.valueAt(i);
+ int channelCount = 0;
+ for (int j = 0; j < r.channels.size();j++) {
+ if (!r.channels.valueAt(j).isDeleted()) {
+ channelCount++;
+ }
+ }
+ packageChannels.put(r.pkg, channelCount);
+ }
+ return packageChannels;
+ }
+
public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
int[] uidList) {
if (pkgList == null || pkgList.length == 0) {
@@ -979,6 +1045,16 @@ public class RankingHelper implements RankingConfig {
}
}
+ private LogMaker getChannelLog(NotificationChannel channel, String pkg) {
+ return new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL)
+ .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+ .setPackageName(pkg)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID,
+ channel.getId())
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE,
+ channel.getImportance());
+ }
+
private static class Record {
static int UNKNOWN_UID = UserHandle.USER_NULL;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a692559129ad..1af541d6587b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -53,9 +53,11 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.util.ConcurrentUtils;
import com.android.server.FgThread;
import com.android.server.IoThread;
import com.android.server.LocalServices;
+import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerService;
@@ -74,6 +76,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -219,6 +222,8 @@ public final class OverlayManagerService extends SystemService {
private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
+ private Future<?> mInitCompleteSignal;
+
public OverlayManagerService(@NonNull final Context context,
@NonNull final Installer installer) {
super(context);
@@ -230,28 +235,29 @@ public final class OverlayManagerService extends SystemService {
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
getDefaultOverlayPackages());
+ mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
+ packageFilter, null, null);
+
+ final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
+ userFilter, null, null);
+
+ restoreSettings();
+ onSwitchUser(UserHandle.USER_SYSTEM);
+ schedulePersistSettings();
- final IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(ACTION_PACKAGE_ADDED);
- packageFilter.addAction(ACTION_PACKAGE_CHANGED);
- packageFilter.addAction(ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme("package");
- getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
- packageFilter, null, null);
-
- final IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(ACTION_USER_REMOVED);
- getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
- userFilter, null, null);
-
- restoreSettings();
- onSwitchUser(UserHandle.USER_SYSTEM);
- schedulePersistSettings();
-
- mSettings.addChangeListener(new OverlayChangeListener());
+ mSettings.addChangeListener(new OverlayChangeListener());
- publishBinderService(Context.OVERLAY_SERVICE, mService);
- publishLocalService(OverlayManagerService.class, this);
+ publishBinderService(Context.OVERLAY_SERVICE, mService);
+ publishLocalService(OverlayManagerService.class, this);
+ }, "Init OverlayManagerService");
}
@Override
@@ -260,6 +266,15 @@ public final class OverlayManagerService extends SystemService {
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
+ "Wait for OverlayManagerService init");
+ mInitCompleteSignal = null;
+ }
+ }
+
+ @Override
public void onSwitchUser(final int newUserId) {
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 837b69e5f7f3..cd0e6ccb2eb4 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -23,12 +23,15 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.animation.Animator;
import android.animation.ValueAnimator;
+import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.WindowManagerInternal;
@@ -51,6 +54,8 @@ public class BoundsAnimationController {
? "BoundsAnimationController" : TAG_WM;
private static final int DEBUG_ANIMATION_SLOW_DOWN_FACTOR = 1;
+ private static final int DEFAULT_TRANSITION_DURATION = 425;
+
// Only accessed on UI thread.
private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
@@ -85,12 +90,15 @@ public class BoundsAnimationController {
private final Handler mHandler;
private final AppTransition mAppTransition;
private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier();
+ private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
- BoundsAnimationController(AppTransition transition, Handler handler) {
+ BoundsAnimationController(Context context, AppTransition transition, Handler handler) {
mHandler = handler;
mAppTransition = transition;
mAppTransition.registerListenerLocked(mAppTransitionNotifier);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
}
private final class BoundsAnimator extends ValueAnimator
@@ -297,8 +305,8 @@ public class BoundsAnimationController {
mRunningAnimations.put(target, animator);
animator.setFloatValues(0f, 1f);
animator.setDuration((animationDuration != -1 ? animationDuration
- : DEFAULT_APP_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
- animator.setInterpolator(new LinearInterpolator());
+ : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
animator.start();
}
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 2a20a70b6ee9..1d50d0d3826f 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -94,13 +94,16 @@ class PinnedStackController {
// The size and position information that describes where the pinned stack will go by default.
private int mDefaultStackGravity;
- private Size mDefaultStackSize;
+ private float mDefaultAspectRatio;
private Point mScreenEdgeInsets;
// The aspect ratio bounds of the PIP.
private float mMinAspectRatio;
private float mMaxAspectRatio;
+ // The minimum edge size of the normal PiP bounds.
+ private int mMinSize;
+
// Temp vars for calculation
private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
private final Rect mTmpInsets = new Rect();
@@ -151,15 +154,15 @@ class PinnedStackController {
*/
void reloadResources() {
final Resources res = mService.mContext.getResources();
- final Size defaultSizeDp = Size.parseSize(res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureSize));
+ mMinSize = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+ mDefaultAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
final Size screenEdgeInsetsDp = Size.parseSize(res.getString(
com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets));
mDefaultStackGravity = res.getInteger(
com.android.internal.R.integer.config_defaultPictureInPictureGravity);
mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
- mDefaultStackSize = new Size(dpToPx(defaultSizeDp.getWidth(), mTmpMetrics),
- dpToPx(defaultSizeDp.getHeight(), mTmpMetrics));
mScreenEdgeInsets = new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
mMinAspectRatio = res.getFloat(
@@ -199,16 +202,13 @@ class PinnedStackController {
* specified aspect ratio.
*/
Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio) {
- // Save the snap fraction, calculate the aspect ratio based on the current bounds
+ // Save the snap fraction, calculate the aspect ratio based on screen size
final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
getMovementBounds(stackBounds));
- final float radius = PointF.length(stackBounds.width(), stackBounds.height());
- final int height = (int) Math.round(Math.sqrt((radius * radius) /
- (aspectRatio * aspectRatio + 1)));
- final int width = Math.round(height * aspectRatio);
- final int left = (int) (stackBounds.centerX() - width / 2f);
- final int top = (int) (stackBounds.centerY() - height / 2f);
- stackBounds.set(left, top, left + width, top + height);
+ final Size size = getSize(aspectRatio);
+ final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
+ final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
+ stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
if (mIsMinimized) {
applyMinimizedOffset(stackBounds, getMovementBounds(stackBounds));
@@ -217,6 +217,14 @@ class PinnedStackController {
}
/**
+ * @return the size of the PIP based on the given {@param aspectRatio}.
+ */
+ Size getSize(float aspectRatio) {
+ return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize,
+ mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+ }
+
+ /**
* @return the default bounds to show the PIP when there is no active PIP.
*/
Rect getDefaultBounds() {
@@ -224,8 +232,9 @@ class PinnedStackController {
getInsetBounds(insetBounds);
final Rect defaultBounds = new Rect();
- Gravity.apply(mDefaultStackGravity, mDefaultStackSize.getWidth(),
- mDefaultStackSize.getHeight(), insetBounds, 0, 0, defaultBounds);
+ final Size size = getSize(mDefaultAspectRatio);
+ Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
+ 0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
return defaultBounds;
}
@@ -344,14 +353,21 @@ class PinnedStackController {
private void notifyMovementBoundsChanged(boolean fromImeAdjustement) {
if (mPinnedStackListener != null) {
try {
- Rect insetBounds = new Rect();
+ final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
- Rect normalBounds = getDefaultBounds();
+ final Rect normalBounds = getDefaultBounds();
if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
transformBoundsToAspectRatio(normalBounds, mAspectRatio);
}
+ final Rect animatingBounds = mTmpRect;
+ final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
+ if (pinnedStack != null) {
+ pinnedStack.getAnimatingBounds(animatingBounds);
+ } else {
+ animatingBounds.set(normalBounds);
+ }
mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
- fromImeAdjustement);
+ animatingBounds, fromImeAdjustement);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eb3a2d15a855..66ec8f0c6176 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1026,8 +1026,8 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
- mBoundsAnimationController =
- new BoundsAnimationController(mAppTransition, UiThread.getHandler());
+ mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
+ UiThread.getHandler());
mActivityManager = ActivityManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 25c29ee9566f..450f9b638c2e 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -15,11 +15,15 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,6 +51,7 @@ import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
import android.util.Xml;
import java.io.BufferedInputStream;
@@ -59,12 +64,14 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ThreadLocalRandom;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -771,6 +778,17 @@ public class RankingHelperTest {
}
@Test
+ public void testCreateChannel_defaultChannelId() throws Exception {
+ try {
+ mHelper.createNotificationChannel(pkg2, uid2, new NotificationChannel(
+ NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true);
+ fail("Allowed to create default channel");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ }
+
+ @Test
public void testCreateChannel_alreadyExists() throws Exception {
long[] vibration = new long[]{100, 67, 145, 156};
NotificationChannel channel =
@@ -974,9 +992,58 @@ public class RankingHelperTest {
assertEquals(2, actual.size());
for (NotificationChannelGroup group : actual) {
- if (Objects.equals(group.getId(),ncg.getId())) {
+ if (Objects.equals(group.getId(), ncg.getId())) {
assertEquals(1, group.getChannels().size());
}
}
}
+
+ @Test
+ public void testCreateChannel_updateNameResId() throws Exception {
+ NotificationChannel nc = new NotificationChannel("id", 1, IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(pkg, uid, nc, true);
+
+ nc = new NotificationChannel("id", 2, IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(pkg, uid, nc, true);
+
+ assertEquals(2, mHelper.getNotificationChannel(pkg, uid, "id", false).getNameResId());
+ }
+
+ @Test
+ public void testDumpChannelsJson() throws Exception {
+ final ApplicationInfo upgrade = new ApplicationInfo();
+ upgrade.targetSdkVersion = Build.VERSION_CODES.O;
+ try {
+ when(mPm.getApplicationInfoAsUser(
+ anyString(), anyInt(), anyInt())).thenReturn(upgrade);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
+ int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
+ for (int i = 0; i < numPackages; i++) {
+ String pkgName = "pkg" + i;
+ int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
+ for (int j = 0; j < numChannels; j++) {
+ mHelper.createNotificationChannel(pkgName, uid,
+ new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true);
+ }
+ expectedChannels.put(pkgName, numChannels);
+ }
+
+ // delete the first channel of the first package
+ String pkg = expectedChannels.keyAt(0);
+ mHelper.deleteNotificationChannel("pkg" + 0, uid, "0");
+ // dump should not include deleted channels
+ int count = expectedChannels.get(pkg);
+ expectedChannels.put(pkg, count - 1);
+
+ JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
+ assertEquals(numPackages, actual.length());
+ for (int i = 0; i < numPackages; i++) {
+ JSONObject object = actual.getJSONObject(i);
+ assertTrue(expectedChannels.containsKey(object.get("packageName")));
+ assertEquals(expectedChannels.get(object.get("packageName")).intValue() + 1,
+ object.getInt("channelCount"));
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 5bb479fdeea5..c79090203c0b 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -878,6 +878,16 @@ public final class Call {
* @param id The ID of the request.
*/
public void onRttRequest(Call call, int id) {}
+
+ /**
+ * Invoked when the RTT session failed to initiate for some reason, including rejection
+ * by the remote party.
+ * @param call The call which the RTT initiation failure occurred on.
+ * @param reason One of the status codes defined in
+ * {@link android.telecom.Connection.RttModifyStatus}, with the exception of
+ * {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
+ */
+ public void onRttInitiationFailure(Call call, int reason) {}
}
/**
@@ -920,13 +930,15 @@ public final class Call {
private OutputStreamWriter mTransmitStream;
private int mRttMode;
private final InCallAdapter mInCallAdapter;
+ private final String mTelecomCallId;
private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
/**
* @hide
*/
- public RttCall(InputStreamReader receiveStream, OutputStreamWriter transmitStream,
- int mode, InCallAdapter inCallAdapter) {
+ public RttCall(String telecomCallId, InputStreamReader receiveStream,
+ OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) {
+ mTelecomCallId = telecomCallId;
mReceiveStream = receiveStream;
mTransmitStream = transmitStream;
mRttMode = mode;
@@ -949,7 +961,7 @@ public final class Call {
* {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
*/
public void setRttMode(@RttAudioMode int mode) {
- mInCallAdapter.setRttMode(mode);
+ mInCallAdapter.setRttMode(mTelecomCallId, mode);
}
/**
@@ -1014,6 +1026,7 @@ public final class Call {
private int mState;
private List<String> mCannedTextResponses = null;
private String mCallingPackage;
+ private int mTargetSdkVersion;
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
private RttCall mRttCall;
@@ -1220,7 +1233,7 @@ public final class Call {
* {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void sendRttRequest() {
- mInCallAdapter.sendRttRequest();
+ mInCallAdapter.sendRttRequest(mTelecomCallId);
}
/**
@@ -1231,7 +1244,7 @@ public final class Call {
* @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
*/
public void respondToRttRequest(int id, boolean accept) {
- mInCallAdapter.respondToRttRequest(id, accept);
+ mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept);
}
/**
@@ -1239,7 +1252,7 @@ public final class Call {
* the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
public void stopRtt() {
- mInCallAdapter.stopRtt();
+ mInCallAdapter.stopRtt(mTelecomCallId);
}
/**
@@ -1547,22 +1560,25 @@ public final class Call {
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage,
+ int targetSdkVersion) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = STATE_NEW;
mCallingPackage = callingPackage;
+ mTargetSdkVersion = targetSdkVersion;
}
/** {@hide} */
Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
- String callingPackage) {
+ String callingPackage, int targetSdkVersion) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = state;
mCallingPackage = callingPackage;
+ mTargetSdkVersion = targetSdkVersion;
}
/** {@hide} */
@@ -1588,7 +1604,8 @@ public final class Call {
cannedTextResponsesChanged = true;
}
- VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
+ VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
+ mTargetSdkVersion);
boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
!Objects.equals(mVideoCallImpl, newVideoCallImpl);
if (videoCallChanged) {
@@ -1644,7 +1661,7 @@ public final class Call {
new ParcelFileDescriptor.AutoCloseOutputStream(
parcelableRttCall.getTransmitStream()),
StandardCharsets.UTF_8);
- RttCall newRttCall = new Call.RttCall(
+ RttCall newRttCall = new Call.RttCall(mTelecomCallId,
receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
if (mRttCall == null) {
isRttChanged = true;
@@ -1724,6 +1741,15 @@ public final class Call {
}
}
+ /** @hide */
+ final void internalOnRttInitiationFailure(int reason) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttInitiationFailure(call, reason));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3e690b997b29..833affa379f3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -20,9 +20,12 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.Notification;
+import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
import android.os.Binder;
@@ -39,6 +42,8 @@ import android.view.Surface;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -764,6 +769,10 @@ public abstract class Connection extends Conferenceable {
/** @hide */
public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
public void onAudioRouteChanged(Connection c, int audioRoute) {}
+ public void onRttInitiationSuccess(Connection c) {}
+ public void onRttInitiationFailure(Connection c, int reason) {}
+ public void onRttSessionRemotelyTerminated(Connection c) {}
+ public void onRemoteRttRequest(Connection c) {}
}
/**
@@ -774,12 +783,16 @@ public abstract class Connection extends Conferenceable {
private static final int READ_BUFFER_SIZE = 1000;
private final InputStreamReader mPipeFromInCall;
private final OutputStreamWriter mPipeToInCall;
+ private final ParcelFileDescriptor mFdFromInCall;
+ private final ParcelFileDescriptor mFdToInCall;
private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
/**
* @hide
*/
public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
+ mFdFromInCall = fromInCall;
+ mFdToInCall = toInCall;
mPipeFromInCall = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
mPipeToInCall = new OutputStreamWriter(
@@ -823,6 +836,47 @@ public abstract class Connection extends Conferenceable {
return null;
}
}
+
+ /** @hide */
+ public ParcelFileDescriptor getFdFromInCall() {
+ return mFdFromInCall;
+ }
+
+ /** @hide */
+ public ParcelFileDescriptor getFdToInCall() {
+ return mFdToInCall;
+ }
+ }
+
+ /**
+ * Provides constants to represent the results of responses to session modify requests sent via
+ * {@link Call#sendRttRequest()}
+ */
+ public static final class RttModifyStatus {
+ /**
+ * Session modify request was successful.
+ */
+ public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1;
+
+ /**
+ * Session modify request failed.
+ */
+ public static final int SESSION_MODIFY_REQUEST_FAIL = 2;
+
+ /**
+ * Session modify request ignored due to invalid parameters.
+ */
+ public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
+
+ /**
+ * Session modify request timed out.
+ */
+ public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
+
+ /**
+ * Session modify request rejected by remote user.
+ */
+ public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
}
/**
@@ -1005,7 +1059,7 @@ public abstract class Connection extends Conferenceable {
try {
onSetCamera((String) args.arg1);
onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
- args.argi2);
+ args.argi2, args.argi3);
} finally {
args.recycle();
}
@@ -1065,7 +1119,9 @@ public abstract class Connection extends Conferenceable {
MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
}
- public void setCamera(String cameraId, String callingPackageName) {
+ public void setCamera(String cameraId, String callingPackageName,
+ int targetSdkVersion) {
+
SomeArgs args = SomeArgs.obtain();
args.arg1 = cameraId;
// Propagate the calling package; originally determined in
@@ -1077,6 +1133,9 @@ public abstract class Connection extends Conferenceable {
// check to see if the calling app is able to use the camera.
args.argi1 = Binder.getCallingUid();
args.argi2 = Binder.getCallingPid();
+ // Pass along the target SDK version of the calling InCallService. This is used to
+ // maintain backwards compatibility of the API for older callers.
+ args.argi3 = targetSdkVersion;
mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
}
@@ -1179,10 +1238,11 @@ public abstract class Connection extends Conferenceable {
* @param callingPackageName The AppOpps package name of the caller.
* @param callingUid The UID of the caller.
* @param callingPid The PID of the caller.
+ * @param targetSdkVersion The target SDK version of the caller.
* @hide
*/
public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
- int callingPid) {}
+ int callingPid, int targetSdkVersion) {}
/**
* Sets the surface to be used for displaying a preview of what the user's camera is
@@ -2426,6 +2486,47 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Informs listeners that a previously requested RTT session via
+ * {@link ConnectionRequest#isRequestingRtt()} or
+ * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} has succeeded.
+ * @hide
+ */
+ public final void sendRttInitiationSuccess() {
+ mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
+ }
+
+ /**
+ * Informs listeners that a previously requested RTT session via
+ * {@link ConnectionRequest#isRequestingRtt()} or
+ * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)}
+ * has failed.
+ * @param reason One of the reason codes defined in {@link RttModifyStatus}, with the
+ * exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
+ * @hide
+ */
+ public final void sendRttInitiationFailure(int reason) {
+ mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
+ }
+
+ /**
+ * Informs listeners that a currently active RTT session has been terminated by the remote
+ * side of the coll.
+ * @hide
+ */
+ public final void sendRttSessionRemotelyTerminated() {
+ mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
+ }
+
+ /**
+ * Informs listeners that the remote side of the call has requested an upgrade to include an
+ * RTT session in the call.
+ * @hide
+ */
+ public final void sendRemoteRttRequest() {
+ mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this));
+ }
+
+ /**
* Notifies this Connection that the {@link #getAudioState()} property has a new value.
*
* @param state The new connection audio state.
@@ -2592,9 +2693,73 @@ public abstract class Connection extends Conferenceable {
* regular {@link ConnectionService}, the Telecom framework will display its own incoming call
* user interface to allow the user to choose whether to answer the new incoming call and
* disconnect other ongoing calls, or to reject the new incoming call.
+ * <p>
+ * You should trigger the display of the incoming call user interface for your application by
+ * showing a {@link Notification} with a full-screen {@link Intent} specified.
+ * For example:
+ * <pre><code>
+ * // Create an intent which triggers your fullscreen incoming call user interface.
+ * Intent intent = new Intent(Intent.ACTION_MAIN, null);
+ * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
+ * intent.setClass(context, YourIncomingCallActivity.class);
+ * PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
+ *
+ * // Build the notification as an ongoing high priority item; this ensures it will show as
+ * // a heads up notification which slides down over top of the current content.
+ * final Notification.Builder builder = new Notification.Builder(context);
+ * builder.setOngoing(true);
+ * builder.setPriority(Notification.PRIORITY_HIGH);
+ *
+ * // Set notification content intent to take user to fullscreen UI if user taps on the
+ * // notification body.
+ * builder.setContentIntent(pendingIntent);
+ * // Set full screen intent to trigger display of the fullscreen UI when the notification
+ * // manager deems it appropriate.
+ * builder.setFullScreenIntent(pendingIntent, true);
+ *
+ * // Setup notification content.
+ * builder.setSmallIcon( yourIconResourceId );
+ * builder.setContentTitle("Your notification title");
+ * builder.setContentText("Your notification content.");
+ *
+ * // Use builder.addAction(..) to add buttons to answer or reject the call.
+ *
+ * NotificationManager notificationManager = mContext.getSystemService(
+ * NotificationManager.class);
+ * notificationManager.notify(YOUR_TAG, YOUR_ID, builder.build());
+ * </code></pre>
*/
public void onShowIncomingCallUi() {}
+ /**
+ * Notifies this {@link Connection} that the user has requested an RTT session.
+ * The connection service should call {@link #sendRttInitiationSuccess} or
+ * {@link #sendRttInitiationFailure} to inform Telecom of the success or failure of the
+ * request, respectively.
+ * @param rttTextStream The object that should be used to send text to or receive text from
+ * the in-call app.
+ * @hide
+ */
+ public void onStartRtt(@NonNull RttTextStream rttTextStream) {}
+
+ /**
+ * Notifies this {@link Connection} that it should terminate any existing RTT communication
+ * channel. No response to Telecom is needed for this method.
+ * @hide
+ */
+ public void onStopRtt() {}
+
+ /**
+ * Notifies this connection of a response to a previous remotely-initiated RTT upgrade
+ * request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is
+ * indicated by the supplied {@link RttTextStream} being non-null, and rejection is
+ * indicated by {@code rttTextStream} being {@code null}
+ * @hide
+ * @param rttTextStream The object that should be used to send text to or receive text from
+ * the in-call app.
+ */
+ public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
+
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 6e100298da35..bf8f8e4e723e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -26,6 +26,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.telecom.Logging.Session;
import com.android.internal.os.SomeArgs;
@@ -119,6 +121,9 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
+ private static final String SESSION_START_RTT = "CS.+RTT";
+ private static final String SESSION_STOP_RTT = "CS.-RTT";
+ private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2;
@@ -144,6 +149,9 @@ public abstract class ConnectionService extends Service {
private static final int MSG_SEND_CALL_EVENT = 23;
private static final int MSG_ON_EXTRAS_CHANGED = 24;
private static final int MSG_CREATE_CONNECTION_FAILED = 25;
+ private static final int MSG_ON_START_RTT = 26;
+ private static final int MSG_ON_STOP_RTT = 27;
+ private static final int MSG_RTT_UPGRADE_RESPONSE = 28;
private static Connection sNullConnection;
@@ -214,6 +222,7 @@ public abstract class ConnectionService extends Service {
@Override
public void createConnectionFailed(
+ PhoneAccountHandle connectionManagerPhoneAccount,
String callId,
ConnectionRequest request,
boolean isIncoming,
@@ -224,6 +233,7 @@ public abstract class ConnectionService extends Service {
args.arg1 = callId;
args.arg2 = request;
args.arg3 = Log.createSubsession();
+ args.arg4 = connectionManagerPhoneAccount;
args.argi1 = isIncoming ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
} finally {
@@ -501,6 +511,53 @@ public abstract class ConnectionService extends Service {
Log.endSession();
}
}
+
+ @Override
+ public void startRtt(String callId, ParcelFileDescriptor fromInCall,
+ ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
+ Log.startSession(sessionInfo, SESSION_START_RTT);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = new Connection.RttTextStream(toInCall, fromInCall);
+ args.arg3 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_ON_START_RTT, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException {
+ Log.startSession(sessionInfo, SESSION_STOP_RTT);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_ON_STOP_RTT, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall,
+ ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
+ Log.startSession(sessionInfo, SESSION_RTT_UPGRADE_RESPONSE);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ if (toInCall == null || fromInCall == null) {
+ args.arg2 = null;
+ } else {
+ args.arg2 = new Connection.RttTextStream(toInCall, fromInCall);
+ }
+ args.arg3 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_RTT_UPGRADE_RESPONSE, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
};
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -581,6 +638,8 @@ public abstract class ConnectionService extends Service {
final String id = (String) args.arg1;
final ConnectionRequest request = (ConnectionRequest) args.arg2;
final boolean isIncoming = args.argi1 == 1;
+ final PhoneAccountHandle connectionMgrPhoneAccount =
+ (PhoneAccountHandle) args.arg4;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init request %s", id);
mPreInitializationConnectionRequests.add(
@@ -589,12 +648,14 @@ public abstract class ConnectionService extends Service {
null /*lock*/) {
@Override
public void loggedRun() {
- createConnectionFailed(id, request, isIncoming);
+ createConnectionFailed(connectionMgrPhoneAccount, id,
+ request, isIncoming);
}
}.prepare());
} else {
Log.i(this, "createConnectionFailed %s", id);
- createConnectionFailed(id, request, isIncoming);
+ createConnectionFailed(connectionMgrPhoneAccount, id, request,
+ isIncoming);
}
} finally {
args.recycle();
@@ -848,6 +909,49 @@ public abstract class ConnectionService extends Service {
}
break;
}
+ case MSG_ON_START_RTT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Log.continueSession((Session) args.arg3,
+ SESSION_HANDLER + SESSION_START_RTT);
+ String callId = (String) args.arg1;
+ Connection.RttTextStream rttTextStream =
+ (Connection.RttTextStream) args.arg2;
+ startRtt(callId, rttTextStream);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+ case MSG_ON_STOP_RTT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Log.continueSession((Session) args.arg2,
+ SESSION_HANDLER + SESSION_STOP_RTT);
+ String callId = (String) args.arg1;
+ stopRtt(callId);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+ case MSG_RTT_UPGRADE_RESPONSE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Log.continueSession((Session) args.arg3,
+ SESSION_HANDLER + SESSION_RTT_UPGRADE_RESPONSE);
+ String callId = (String) args.arg1;
+ Connection.RttTextStream rttTextStream =
+ (Connection.RttTextStream) args.arg2;
+ handleRttUpgradeResponse(callId, rttTextStream);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
default:
break;
}
@@ -1136,6 +1240,38 @@ public abstract class ConnectionService extends Service {
mAdapter.setAudioRoute(id, audioRoute);
}
}
+
+ @Override
+ public void onRttInitiationSuccess(Connection c) {
+ String id = mIdByConnection.get(c);
+ if (id != null) {
+ mAdapter.onRttInitiationSuccess(id);
+ }
+ }
+
+ @Override
+ public void onRttInitiationFailure(Connection c, int reason) {
+ String id = mIdByConnection.get(c);
+ if (id != null) {
+ mAdapter.onRttInitiationFailure(id, reason);
+ }
+ }
+
+ @Override
+ public void onRttSessionRemotelyTerminated(Connection c) {
+ String id = mIdByConnection.get(c);
+ if (id != null) {
+ mAdapter.onRttSessionRemotelyTerminated(id);
+ }
+ }
+
+ @Override
+ public void onRemoteRttRequest(Connection c) {
+ String id = mIdByConnection.get(c);
+ if (id != null) {
+ mAdapter.onRemoteRttRequest(id);
+ }
+ }
};
/** {@inheritDoc} */
@@ -1225,14 +1361,15 @@ public abstract class ConnectionService extends Service {
}
}
- private void createConnectionFailed(final String callId, final ConnectionRequest request,
- boolean isIncoming) {
+ private void createConnectionFailed(final PhoneAccountHandle callManagerAccount,
+ final String callId, final ConnectionRequest request,
+ boolean isIncoming) {
Log.i(this, "createConnectionFailed %s", callId);
if (isIncoming) {
- onCreateIncomingConnectionFailed(request);
+ onCreateIncomingConnectionFailed(callManagerAccount, request);
} else {
- onCreateOutgoingConnectionFailed(request);
+ onCreateOutgoingConnectionFailed(callManagerAccount, request);
}
}
@@ -1430,7 +1567,6 @@ public abstract class ConnectionService extends Service {
if (connection != null) {
connection.onCallEvent(event, extras);
}
-
}
/**
@@ -1454,6 +1590,34 @@ public abstract class ConnectionService extends Service {
}
}
+ private void startRtt(String callId, Connection.RttTextStream rttTextStream) {
+ Log.d(this, "startRtt(%s)", callId);
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "startRtt").onStartRtt(rttTextStream);
+ } else if (mConferenceById.containsKey(callId)) {
+ Log.w(this, "startRtt called on a conference.");
+ }
+ }
+
+ private void stopRtt(String callId) {
+ Log.d(this, "stopRtt(%s)", callId);
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "stopRtt").onStopRtt();
+ } else if (mConferenceById.containsKey(callId)) {
+ Log.w(this, "stopRtt called on a conference.");
+ }
+ }
+
+ private void handleRttUpgradeResponse(String callId, Connection.RttTextStream rttTextStream) {
+ Log.d(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "handleRttUpgradeResponse")
+ .handleRttUpgradeResponse(rttTextStream);
+ } else if (mConferenceById.containsKey(callId)) {
+ Log.w(this, "handleRttUpgradeResponse called on a conference.");
+ }
+ }
+
private void onPostDialContinue(String callId, boolean proceed) {
Log.d(this, "onPostDialContinue(%s)", callId);
findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
@@ -1682,9 +1846,12 @@ public abstract class ConnectionService extends Service {
* <p>
* See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
*
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
*/
- public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
+ public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
}
/**
@@ -1698,9 +1865,12 @@ public abstract class ConnectionService extends Service {
* <p>
* See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
*
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
*/
- public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
+ public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
}
/**
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 9542b73c68fb..63bdf74d383c 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -547,4 +547,66 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
}
}
+
+ /**
+ * Notifies Telecom that an RTT session was successfully established.
+ *
+ * @param callId The unique ID of the call.
+ */
+ void onRttInitiationSuccess(String callId) {
+ Log.v(this, "onRttInitiationSuccess: %s", callId);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onRttInitiationSuccess(callId, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Notifies Telecom that a requested RTT session failed to be established.
+ *
+ * @param callId The unique ID of the call.
+ */
+ void onRttInitiationFailure(String callId, int reason) {
+ Log.v(this, "onRttInitiationFailure: %s", callId);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onRttInitiationFailure(callId, reason, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Notifies Telecom that an established RTT session was terminated by the remote user on
+ * the call.
+ *
+ * @param callId The unique ID of the call.
+ */
+ void onRttSessionRemotelyTerminated(String callId) {
+ Log.v(this, "onRttSessionRemotelyTerminated: %s", callId);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onRttSessionRemotelyTerminated(callId, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Notifies Telecom that the remote user on the call has requested an upgrade to an RTT
+ * session for this call.
+ *
+ * @param callId The unique ID of the call.
+ */
+ void onRemoteRttRequest(String callId) {
+ Log.v(this, "onRemoteRttRequest: %s", callId);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onRemoteRttRequest(callId, Log.getExternalSession());
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index cc437f9c7cd0..80e3c33a443d 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -68,6 +68,10 @@ final class ConnectionServiceAdapterServant {
private static final int MSG_SET_CONNECTION_PROPERTIES = 27;
private static final int MSG_SET_PULLING = 28;
private static final int MSG_SET_AUDIO_ROUTE = 29;
+ private static final int MSG_ON_RTT_INITIATION_SUCCESS = 30;
+ private static final int MSG_ON_RTT_INITIATION_FAILURE = 31;
+ private static final int MSG_ON_RTT_REMOTELY_TERMINATED = 32;
+ private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33;
private final IConnectionServiceAdapter mDelegate;
@@ -300,6 +304,20 @@ final class ConnectionServiceAdapterServant {
}
break;
}
+ case MSG_ON_RTT_INITIATION_SUCCESS:
+ mDelegate.onRttInitiationSuccess((String) msg.obj, null /*Session.Info*/);
+ break;
+ case MSG_ON_RTT_INITIATION_FAILURE:
+ mDelegate.onRttInitiationFailure((String) msg.obj, msg.arg1,
+ null /*Session.Info*/);
+ break;
+ case MSG_ON_RTT_REMOTELY_TERMINATED:
+ mDelegate.onRttSessionRemotelyTerminated((String) msg.obj,
+ null /*Session.Info*/);
+ break;
+ case MSG_ON_RTT_UPGRADE_REQUEST:
+ mDelegate.onRemoteRttRequest((String) msg.obj, null /*Session.Info*/);
+ break;
}
}
};
@@ -537,6 +555,32 @@ final class ConnectionServiceAdapterServant {
args.arg3 = extras;
mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
}
+
+ @Override
+ public void onRttInitiationSuccess(String connectionId, Session.Info sessionInfo)
+ throws RemoteException {
+ mHandler.obtainMessage(MSG_ON_RTT_INITIATION_SUCCESS, connectionId).sendToTarget();
+ }
+
+ @Override
+ public void onRttInitiationFailure(String connectionId, int reason,
+ Session.Info sessionInfo)
+ throws RemoteException {
+ mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, connectionId)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onRttSessionRemotelyTerminated(String connectionId, Session.Info sessionInfo)
+ throws RemoteException {
+ mHandler.obtainMessage(MSG_ON_RTT_REMOTELY_TERMINATED, connectionId).sendToTarget();
+ }
+
+ @Override
+ public void onRemoteRttRequest(String connectionId, Session.Info sessionInfo)
+ throws RemoteException {
+ mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, connectionId).sendToTarget();
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index d640b1dd6022..9559a28c0bef 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -379,9 +379,9 @@ public final class InCallAdapter {
/**
* Sends an RTT upgrade request to the remote end of the connection.
*/
- public void sendRttRequest() {
+ public void sendRttRequest(String callId) {
try {
- mAdapter.sendRttRequest();
+ mAdapter.sendRttRequest(callId);
} catch (RemoteException ignored) {
}
}
@@ -392,9 +392,9 @@ public final class InCallAdapter {
* @param id the ID of the request as specified by Telecom
* @param accept Whether the request should be accepted.
*/
- public void respondToRttRequest(int id, boolean accept) {
+ public void respondToRttRequest(String callId, int id, boolean accept) {
try {
- mAdapter.respondToRttRequest(id, accept);
+ mAdapter.respondToRttRequest(callId, id, accept);
} catch (RemoteException ignored) {
}
}
@@ -402,9 +402,9 @@ public final class InCallAdapter {
/**
* Instructs Telecom to shut down the RTT communication channel.
*/
- public void stopRtt() {
+ public void stopRtt(String callId) {
try {
- mAdapter.stopRtt();
+ mAdapter.stopRtt(callId);
} catch (RemoteException ignored) {
}
}
@@ -413,9 +413,9 @@ public final class InCallAdapter {
* Sets the RTT audio mode.
* @param mode the desired RTT audio mode
*/
- public void setRttMode(int mode) {
+ public void setRttMode(String callId, int mode) {
try {
- mAdapter.setRttMode(mode);
+ mAdapter.setRttMode(callId, mode);
} catch (RemoteException ignored) {
}
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 4bc64c05bfee..e384d4696ab0 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -77,6 +77,7 @@ public abstract class InCallService extends Service {
private static final int MSG_SILENCE_RINGER = 8;
private static final int MSG_ON_CONNECTION_EVENT = 9;
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
+ private static final int MSG_ON_RTT_INITIATION_FAILURE = 11;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -89,7 +90,8 @@ public abstract class InCallService extends Service {
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
String callingPackage = getApplicationContext().getOpPackageName();
- mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
+ mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage,
+ getApplicationContext().getApplicationInfo().targetSdkVersion);
mPhone.addListener(mPhoneListener);
onPhoneCreated(mPhone);
break;
@@ -140,6 +142,12 @@ public abstract class InCallService extends Service {
mPhone.internalOnRttUpgradeRequest(callId, requestId);
break;
}
+ case MSG_ON_RTT_INITIATION_FAILURE: {
+ String callId = (String) msg.obj;
+ int reason = msg.arg1;
+ mPhone.internalOnRttInitiationFailure(callId, reason);
+ break;
+ }
default:
break;
}
@@ -210,6 +218,11 @@ public abstract class InCallService extends Service {
public void onRttUpgradeRequest(String callId, int id) {
mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
}
+
+ @Override
+ public void onRttInitiationFailure(String callId, int reason) {
+ mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 975aa5a332ca..85a92d1a135a 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -193,13 +193,16 @@ public final class ParcelableCall implements Parcelable {
/**
* Returns an object for remotely communicating through the video call provider's binder.
-
+ *
+ * @param callingPackageName the package name of the calling InCallService.
+ * @param targetSdkVersion the target SDK version of the calling InCallService.
* @return The video call.
*/
- public VideoCallImpl getVideoCallImpl(String callingPackageName) {
+ public VideoCallImpl getVideoCallImpl(String callingPackageName, int targetSdkVersion) {
if (mVideoCall == null && mVideoCallProvider != null) {
try {
- mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
+ mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName,
+ targetSdkVersion);
} catch (RemoteException ignored) {
// Ignore RemoteException.
}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index ebd04c7cd666..066f6c26dd52 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -127,14 +127,20 @@ public final class Phone {
private final String mCallingPackage;
- Phone(InCallAdapter adapter, String callingPackage) {
+ /**
+ * The Target SDK version of the InCallService implementation.
+ */
+ private final int mTargetSdkVersion;
+
+ Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
mInCallAdapter = adapter;
mCallingPackage = callingPackage;
+ mTargetSdkVersion = targetSdkVersion;
}
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
- parcelableCall.getState(), mCallingPackage);
+ parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
@@ -208,6 +214,13 @@ public final class Phone {
}
}
+ final void internalOnRttInitiationFailure(String callId, int reason) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnRttInitiationFailure(reason);
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 77e0e5486127..57fc9ced91ae 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -20,6 +20,7 @@ import com.android.internal.telecom.IConnectionService;
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
@@ -231,6 +232,41 @@ public final class RemoteConnection {
* @param extras Extras associated with the event.
*/
public void onConnectionEvent(RemoteConnection connection, String event, Bundle extras) {}
+
+ /**
+ * Indicates that a RTT session was successfully established on this
+ * {@link RemoteConnection}. See {@link Connection#sendRttInitiationSuccess()}.
+ * @hide
+ * @param connection The {@code RemoteConnection} invoking this method.
+ */
+ public void onRttInitiationSuccess(RemoteConnection connection) {}
+
+ /**
+ * Indicates that a RTT session failed to be established on this
+ * {@link RemoteConnection}. See {@link Connection#sendRttInitiationFailure()}.
+ * @hide
+ * @param connection The {@code RemoteConnection} invoking this method.
+ * @param reason One of the reason codes defined in {@link Connection.RttModifyStatus},
+ * with the exception of
+ * {@link Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
+ */
+ public void onRttInitiationFailure(RemoteConnection connection, int reason) {}
+
+ /**
+ * Indicates that an established RTT session was terminated remotely on this
+ * {@link RemoteConnection}. See {@link Connection#sendRttSessionRemotelyTerminated()}
+ * @hide
+ * @param connection The {@code RemoteConnection} invoking this method.
+ */
+ public void onRttSessionRemotelyTerminated(RemoteConnection connection) {}
+
+ /**
+ * Indicates that the remote user on this {@link RemoteConnection} has requested an upgrade
+ * to an RTT session. See {@link Connection#sendRemoteRttRequest()}
+ * @hide
+ * @param connection The {@code RemoteConnection} invoking this method.
+ */
+ public void onRemoteRttRequest(RemoteConnection connection) {}
}
/**
@@ -410,6 +446,8 @@ public final class RemoteConnection {
private final String mCallingPackage;
+ private final int mTargetSdkVersion;
+
/**
* ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
* load factor before resizing, 1 means we only expect a single thread to
@@ -418,9 +456,12 @@ public final class RemoteConnection {
private final Set<Callback> mCallbacks = Collections.newSetFromMap(
new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
- VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
+ VideoProvider(IVideoProvider videoProviderBinder, String callingPackage,
+ int targetSdkVersion) {
+
mVideoProviderBinder = videoProviderBinder;
mCallingPackage = callingPackage;
+ mTargetSdkVersion = targetSdkVersion;
try {
mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
} catch (RemoteException e) {
@@ -455,7 +496,7 @@ public final class RemoteConnection {
*/
public void setCamera(String cameraId) {
try {
- mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
+ mVideoProviderBinder.setCamera(cameraId, mCallingPackage, mTargetSdkVersion);
} catch (RemoteException e) {
}
}
@@ -631,7 +672,7 @@ public final class RemoteConnection {
* @hide
*/
RemoteConnection(String callId, IConnectionService connectionService,
- ParcelableConnection connection, String callingPackage) {
+ ParcelableConnection connection, String callingPackage, int targetSdkVersion) {
mConnectionId = callId;
mConnectionService = connectionService;
mConnected = true;
@@ -643,7 +684,8 @@ public final class RemoteConnection {
mVideoState = connection.getVideoState();
IVideoProvider videoProvider = connection.getVideoProvider();
if (videoProvider != null) {
- mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
+ mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage,
+ targetSdkVersion);
} else {
mVideoProvider = null;
}
@@ -1046,6 +1088,61 @@ public final class RemoteConnection {
}
/**
+ * Notifies this {@link RemoteConnection} that the user has requested an RTT session.
+ * @param rttTextStream The object that should be used to send text to or receive text from
+ * the in-call app.
+ * @hide
+ */
+ public void startRtt(@NonNull Connection.RttTextStream rttTextStream) {
+ try {
+ if (mConnected) {
+ mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(),
+ rttTextStream.getFdToInCall(), null /*Session.Info*/);
+ }
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Notifies this {@link RemoteConnection} that it should terminate any existing RTT
+ * session. No response to Telecom is needed for this method.
+ * @hide
+ */
+ public void stopRtt() {
+ try {
+ if (mConnected) {
+ mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/);
+ }
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Notifies this {@link RemoteConnection} of a response to a previous remotely-initiated RTT
+ * upgrade request sent via {@link Connection#sendRemoteRttRequest}.
+ * Acceptance of the request is indicated by the supplied {@link RttTextStream} being non-null,
+ * and rejection is indicated by {@code rttTextStream} being {@code null}
+ * @hide
+ * @param rttTextStream The object that should be used to send text to or receive text from
+ * the in-call app.
+ */
+ public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) {
+ try {
+ if (mConnected) {
+ if (rttTextStream == null) {
+ mConnectionService.respondToRttUpgradeRequest(mConnectionId,
+ null, null, null /*Session.Info*/);
+ } else {
+ mConnectionService.respondToRttUpgradeRequest(mConnectionId,
+ rttTextStream.getFdFromInCall(), rttTextStream.getFdToInCall(),
+ null /*Session.Info*/);
+ }
+ }
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
* Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be
* successfully asked to create a conference with.
*
@@ -1411,6 +1508,47 @@ public final class RemoteConnection {
}
}
+ /** @hide */
+ void onRttInitiationSuccess() {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(
+ () -> callback.onRttInitiationSuccess(connection));
+ }
+ }
+
+ /** @hide */
+ void onRttInitiationFailure(int reason) {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(
+ () -> callback.onRttInitiationFailure(connection, reason));
+ }
+ }
+
+ /** @hide */
+ void onRttSessionRemotelyTerminated() {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(
+ () -> callback.onRttSessionRemotelyTerminated(connection));
+ }
+ }
+
+ /** @hide */
+ void onRemoteRttRequest() {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(
+ () -> callback.onRemoteRttRequest(connection));
+ }
+ }
+
+ /**
/**
* Create a RemoteConnection represents a failure, and which will be in
* {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 60a40f5261dd..06cdd1aa7c3c 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -286,10 +286,11 @@ final class RemoteConnectionService {
String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
.getOpPackageName();
+ int targetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo().targetSdkVersion;
RemoteConnection.VideoProvider remoteVideoProvider = null;
if (videoProvider != null) {
remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
- callingPackage);
+ callingPackage, targetSdkVersion);
}
findConnectionForAction(callId, "setVideoProvider")
.setVideoProvider(remoteVideoProvider);
@@ -357,8 +358,11 @@ final class RemoteConnectionService {
Session.Info sessionInfo) {
String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
getOpPackageName();
+ int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
+ .targetSdkVersion;
RemoteConnection remoteConnection = new RemoteConnection(callId,
- mOutgoingConnectionServiceRpc, connection, callingPackage);
+ mOutgoingConnectionServiceRpc, connection, callingPackage,
+ callingTargetSdkVersion);
mConnectionById.put(callId, remoteConnection);
remoteConnection.registerCallback(new RemoteConnection.Callback() {
@Override
@@ -405,6 +409,50 @@ final class RemoteConnectionService {
extras);
}
}
+
+ @Override
+ public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "onRttInitiationSuccess")
+ .onRttInitiationSuccess();
+ } else {
+ Log.w(this, "onRttInitiationSuccess called on a remote conference");
+ }
+ }
+
+ @Override
+ public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
+ throws RemoteException {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "onRttInitiationFailure")
+ .onRttInitiationFailure(reason);
+ } else {
+ Log.w(this, "onRttInitiationFailure called on a remote conference");
+ }
+ }
+
+ @Override
+ public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "onRttSessionRemotelyTerminated")
+ .onRttSessionRemotelyTerminated();
+ } else {
+ Log.w(this, "onRttSessionRemotelyTerminated called on a remote conference");
+ }
+ }
+
+ @Override
+ public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
+ throws RemoteException {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "onRemoteRttRequest")
+ .onRemoteRttRequest();
+ } else {
+ Log.w(this, "onRemoteRttRequest called on a remote conference");
+ }
+ }
};
private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index d8ede5c21316..429a434992c5 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -44,6 +44,7 @@ public class VideoCallImpl extends VideoCall {
private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
private final String mCallingPackageName;
+ private final int mTargetSdkVersion;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -198,13 +199,15 @@ public class VideoCallImpl extends VideoCall {
private Handler mHandler;
- VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
+ VideoCallImpl(IVideoProvider videoProvider, String callingPackageName, int targetSdkVersion)
+ throws RemoteException {
mVideoProvider = videoProvider;
mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
mBinder = new VideoCallListenerBinder();
mVideoProvider.addVideoCallback(mBinder);
mCallingPackageName = callingPackageName;
+ mTargetSdkVersion = targetSdkVersion;
}
public void destroy() {
@@ -243,7 +246,7 @@ public class VideoCallImpl extends VideoCall {
public void setCamera(String cameraId) {
try {
Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
- mVideoProvider.setCamera(cameraId, mCallingPackageName);
+ mVideoProvider.setCamera(cameraId, mCallingPackageName, mTargetSdkVersion);
} catch (RemoteException e) {
}
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 20feba78f5c9..c631d085f6e7 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telecom;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.telecom.CallAudioState;
import android.telecom.ConnectionRequest;
import android.telecom.Logging.Session;
@@ -46,8 +47,8 @@ oneway interface IConnectionService {
boolean isUnknown,
in Session.Info sessionInfo);
- void createConnectionFailed(String callId, in ConnectionRequest request, boolean isIncoming,
- in Session.Info sessionInfo);
+ void createConnectionFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
+ in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
void abort(String callId, in Session.Info sessionInfo);
@@ -89,4 +90,12 @@ oneway interface IConnectionService {
void sendCallEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo);
void onExtrasChanged(String callId, in Bundle extras, in Session.Info sessionInfo);
+
+ void startRtt(String callId, in ParcelFileDescriptor fromInCall,
+ in ParcelFileDescriptor toInCall, in Session.Info sessionInfo);
+
+ void stopRtt(String callId, in Session.Info sessionInfo);
+
+ void respondToRttUpgradeRequest(String callId, in ParcelFileDescriptor fromInCall,
+ in ParcelFileDescriptor toInCall, in Session.Info sessionInfo);
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index b58f8bc7a0aa..ac9da2ef9df4 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -106,4 +106,12 @@ oneway interface IConnectionServiceAdapter {
void onConnectionEvent(String callId, String event, in Bundle extras,
in Session.Info sessionInfo);
+
+ void onRttInitiationSuccess(String callId, in Session.Info sessionInfo);
+
+ void onRttInitiationFailure(String callId, int reason, in Session.Info sessionInfo);
+
+ void onRttSessionRemotelyTerminated(String callId, in Session.Info sessionInfo);
+
+ void onRemoteRttRequest(String callId, in Session.Info sessionInfo);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 47c3e6cfc3d5..73fa29af2ca4 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -70,11 +70,11 @@ oneway interface IInCallAdapter {
void removeExtras(String callId, in List<String> keys);
- void sendRttRequest();
+ void sendRttRequest(String callId);
- void respondToRttRequest(int id, boolean accept);
+ void respondToRttRequest(String callId, int id, boolean accept);
- void stopRtt();
+ void stopRtt(String callId);
- void setRttMode(int mode);
+ void setRttMode(String callId, int mode);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 1f92e0c42443..e8cf8e975444 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -52,4 +52,6 @@ oneway interface IInCallService {
void onConnectionEvent(String callId, String event, in Bundle extras);
void onRttUpgradeRequest(String callId, int id);
+
+ void onRttInitiationFailure(String callId, int reason);
}
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index a109e90243fe..272b884bd200 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@ oneway interface IVideoProvider {
void removeVideoCallback(IBinder videoCallbackBinder);
- void setCamera(String cameraId, in String mCallingPackageName);
+ void setCamera(String cameraId, in String mCallingPackageName, int targetSdkVersion);
void setPreviewSurface(in Surface surface);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c05045ebd18d..04443a53527c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1176,15 +1176,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
-
- final boolean HAS_DATASYNC_ON_AVAILABLE = false;
- if (HAS_DATASYNC_ON_AVAILABLE) {
- if (expectSuspended) {
- expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
- }
- expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ if (expectSuspended) {
+ expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
}
+ expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
}
void expectAvailableCallbacks(MockNetworkAgent agent) {
@@ -1196,7 +1192,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ expectAvailableCallbacks(agent, false, TIMEOUT_MS);
expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
}
@@ -1937,20 +1933,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
- // Request a NetworkCapabilities update; only the requesting callback is notified.
- // TODO: Delete this together with Connectivity{Manager,Service} code.
- mCm.requestNetworkCapabilities(dfltNetworkCallback);
- dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- dfltNetworkCallback.assertNoCallback();
-
- // Request a LinkProperties update; only the requesting callback is notified.
- // TODO: Delete this together with Connectivity{Manager,Service} code.
- mCm.requestLinkProperties(dfltNetworkCallback);
- dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- dfltNetworkCallback.assertNoCallback();
-
mCm.unregisterNetworkCallback(dfltNetworkCallback);
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
diff --git a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
index fcd63ea993c8..499e58a5d4e5 100644
--- a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
@@ -40,7 +40,7 @@ public class Hyphenator_Delegate {
}
/*package*/ @SuppressWarnings("UnusedParameters") // TODO implement this.
- static long loadHyphenator(ByteBuffer buffer, int offset) {
+ static long loadHyphenator(ByteBuffer buffer, int offset, int minPrefix, int minSuffix) {
return sDelegateManager.addNewDelegate(new Hyphenator_Delegate());
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index 970c7d577c51..1b9901594f6e 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -53,8 +53,9 @@ public class StaticLayout_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long nLoadHyphenator(ByteBuffer buf, int offset) {
- return Hyphenator_Delegate.loadHyphenator(buf, offset);
+ /*package*/ static long nLoadHyphenator(ByteBuffer buf, int offset, int minPrefix,
+ int minSuffix) {
+ return Hyphenator_Delegate.loadHyphenator(buf, offset, minPrefix, minSuffix);
}
@LayoutlibDelegate