Merge "Request vendor info option (43) to get metered hint" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 6a514a4..20f8de1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22280,7 +22280,7 @@
method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void unsubscribe(java.lang.String);
- method public void unsubscribe(java.lang.String, android.os.Bundle);
+ method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
}
@@ -36145,6 +36145,7 @@
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List<android.telecom.Connection> getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36172,6 +36173,7 @@
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -36201,6 +36203,7 @@
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -36226,6 +36229,7 @@
method public void onUnhold();
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
+ method public static java.lang.String propertiesToString(int);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -36234,6 +36238,7 @@
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final deprecated void setExtras(android.os.Bundle);
@@ -36250,12 +36255,11 @@
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
- field public static final int CAPABILITY_CAN_PULL_CALL = 33554432; // 0x2000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
- field public static final int CAPABILITY_IS_EXTERNAL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
field public static final int CAPABILITY_MUTE = 64; // 0x40
@@ -36273,6 +36277,7 @@
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -36495,6 +36500,7 @@
method public void disconnect();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final java.util.List<android.telecom.RemoteConnection> getConnections();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
@@ -36517,6 +36523,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36535,6 +36542,7 @@
method public android.telecom.RemoteConference getConference();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -36564,6 +36572,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9477354..5cbdec3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -23845,7 +23845,7 @@
method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void unsubscribe(java.lang.String);
- method public void unsubscribe(java.lang.String, android.os.Bundle);
+ method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
}
@@ -38714,6 +38714,7 @@
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
method public final deprecated long getConnectTimeMillis();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List<android.telecom.Connection> getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -38744,6 +38745,7 @@
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final deprecated void setConnectTimeMillis(long);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -38774,6 +38776,7 @@
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -38800,6 +38803,7 @@
method public void onUnhold();
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
+ method public static java.lang.String propertiesToString(int);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -38808,6 +38812,7 @@
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final deprecated void setExtras(android.os.Bundle);
@@ -38824,12 +38829,11 @@
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
- field public static final int CAPABILITY_CAN_PULL_CALL = 33554432; // 0x2000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
- field public static final int CAPABILITY_IS_EXTERNAL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
field public static final int CAPABILITY_MUTE = 64; // 0x40
@@ -38847,6 +38851,7 @@
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -39124,6 +39129,7 @@
method public void disconnect();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final java.util.List<android.telecom.RemoteConnection> getConnections();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
@@ -39147,6 +39153,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -39165,6 +39172,7 @@
method public android.telecom.RemoteConference getConference();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -39195,6 +39203,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 1303212..17e20a6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -22345,7 +22345,7 @@
method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
method public void unsubscribe(java.lang.String);
- method public void unsubscribe(java.lang.String, android.os.Bundle);
+ method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
}
@@ -36216,6 +36216,7 @@
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List<android.telecom.Connection> getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36243,6 +36244,7 @@
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -36272,6 +36274,7 @@
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -36297,6 +36300,7 @@
method public void onUnhold();
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
+ method public static java.lang.String propertiesToString(int);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -36305,6 +36309,7 @@
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final deprecated void setExtras(android.os.Bundle);
@@ -36321,12 +36326,11 @@
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
- field public static final int CAPABILITY_CAN_PULL_CALL = 33554432; // 0x2000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
- field public static final int CAPABILITY_IS_EXTERNAL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
field public static final int CAPABILITY_MUTE = 64; // 0x40
@@ -36344,6 +36348,7 @@
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -36566,6 +36571,7 @@
method public void disconnect();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final java.util.List<android.telecom.RemoteConnection> getConnections();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
@@ -36588,6 +36594,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36606,6 +36613,7 @@
method public android.telecom.RemoteConference getConference();
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -36635,6 +36643,7 @@
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2d33a2c..6380801 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
@@ -1790,7 +1791,7 @@
public int taskWidth;
public int taskHeight;
- public int screenOrientation;
+ public int screenOrientation = Configuration.ORIENTATION_UNDEFINED;
public TaskThumbnailInfo() {
// Do nothing
@@ -1807,7 +1808,16 @@
public void reset() {
taskWidth = 0;
taskHeight = 0;
- screenOrientation = 0;
+ screenOrientation = Configuration.ORIENTATION_UNDEFINED;
+ }
+
+ /**
+ * Copies from another ThumbnailInfo.
+ */
+ public void copyFrom(TaskThumbnailInfo o) {
+ taskWidth = o.taskWidth;
+ taskHeight = o.taskHeight;
+ screenOrientation = o.screenOrientation;
}
/** @hide */
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 58d3d91..c0716e9 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -26,12 +26,4 @@
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
<string translatable="false" name="config_defaultPictureInPictureBounds">"1328 54 1808 324"</string>
-
- <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
- is located in center. -->
- <string translatable="false" name="config_centeredPictureInPictureBounds">"596 280 1324 690"</string>
-
- <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
- when the PIP is shown with Recents. -->
- <string translatable="false" name="config_pictureInPictureBoundsInRecents">"1484 96 1804 276"</string>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 01b2c47..6ecaa1f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2462,14 +2462,6 @@
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
<string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
- <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
- is located in center. -->
- <string translatable="false" name="config_centeredPictureInPictureBounds">"0 0 300 300"</string>
-
- <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
- when the PIP is shown with Recents. -->
- <string translatable="false" name="config_pictureInPictureBoundsInRecents">"0 0 100 100"</string>
-
<!-- Controls the snap mode for the docked stack divider
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 081d613..9b7b1d4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -22,6 +22,8 @@
<dimen name="thumbnail_width">192dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
<dimen name="thumbnail_height">192dp</dimen>
+ <!-- The amount to scale a fullscreen screenshot thumbnail. -->
+ <item name="thumbnail_fullscreen_scale" type="fraction">60%</item>
<!-- The standard size (both width and height) of an application icon that
will be displayed in the app launcher and elsewhere. -->
<dimen name="app_icon_size">48dip</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ce7d80b..7426ddf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -308,8 +308,6 @@
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
<java-symbol type="string" name="config_defaultPictureInPictureBounds" />
- <java-symbol type="string" name="config_centeredPictureInPictureBounds" />
- <java-symbol type="string" name="config_pictureInPictureBoundsInRecents" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -1513,6 +1511,7 @@
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
+ <java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index fe2796c..c1805cb 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -57,8 +57,9 @@
* <h3>Standard Extra Data</h3>
*
* <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)}, {@link #unsubscribe(String, Bundle)},
- * and {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
+ * {@link #subscribe(String, Bundle, SubscriptionCallback)},
+ * {@link #unsubscribe(String, SubscriptionCallback)}, and
+ * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
*
* <ul>
* <li> {@link #EXTRA_PAGE}
@@ -383,7 +384,7 @@
}
/**
- * Unsubscribes for changes to the children of the specified media id.
+ * Unsubscribes for changes to the children of the specified media id through a callback.
* <p>
* The query callback will no longer be invoked for results associated with
* this id once this method returns.
@@ -391,13 +392,13 @@
*
* @param parentId The id of the parent media item whose list of children
* will be unsubscribed.
- * @param options A bundle sent to the media browse service to subscribe.
+ * @param callback A callback sent to the media browse service to subscribe.
*/
- public void unsubscribe(@NonNull String parentId, @NonNull Bundle options) {
- if (options == null) {
- throw new IllegalArgumentException("options are null");
+ public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback is null");
}
- unsubscribeInternal(parentId, options);
+ unsubscribeInternal(parentId, callback);
}
/**
@@ -490,7 +491,7 @@
}
}
- private void unsubscribeInternal(String parentId, Bundle options) {
+ private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
// Check arguments.
if (TextUtils.isEmpty(parentId)) {
throw new IllegalArgumentException("parentId is empty.");
@@ -500,16 +501,21 @@
Subscription sub = mSubscriptions.get(parentId);
// Tell the service if necessary.
- if (sub != null && sub.removeCallback(options) && mState == CONNECT_STATE_CONNECTED) {
+ if (mState == CONNECT_STATE_CONNECTED && sub != null) {
try {
- // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
- // it will break the action of support library which expects removeSubscription will
- // be called when options are null.
- if (options == null) {
+ if (callback == null) {
mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
} else {
- mServiceBinder.removeSubscriptionWithOptions(
- parentId, options, mServiceCallbacks);
+ final List<SubscriptionCallback> callbacks = sub.getCallbacks();
+ final List<Bundle> optionsList = sub.getOptionsList();
+ for (int i = callbacks.size() - 1; i >= 0; --i) {
+ if (callbacks.get(i) == callback) {
+ mServiceBinder.removeSubscriptionWithOptions(
+ parentId, optionsList.get(i), mServiceCallbacks);
+ callbacks.remove(i);
+ optionsList.remove(i);
+ }
+ }
}
} catch (RemoteException ex) {
// Process is crashing. We will disconnect, and upon reconnect we will
@@ -517,7 +523,8 @@
Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
}
}
- if (sub != null && sub.isEmpty()) {
+
+ if (sub != null && (sub.isEmpty() || callback == null)) {
mSubscriptions.remove(parentId);
}
}
@@ -1118,16 +1125,5 @@
mCallbacks.add(callback);
mOptionsList.add(options);
}
-
- public boolean removeCallback(Bundle options) {
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- mCallbacks.remove(i);
- mOptionsList.remove(i);
- return true;
- }
- }
- return false;
- }
}
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index f593685..ae86632 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -574,6 +574,9 @@
* Remove the subscription.
*/
private boolean removeSubscription(String id, ConnectionRecord connection, Bundle options) {
+ if (options == null) {
+ return connection.subscriptions.remove(id) != null;
+ }
boolean removed = false;
List<Bundle> optionsList = connection.subscriptions.get(id);
if (optionsList != null) {
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index 2b44d51..1d4ed1d 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -51,6 +51,7 @@
static jclass app_fuse_class;
static jmethodID app_fuse_get_file_size;
static jmethodID app_fuse_read_object_bytes;
+static jmethodID app_fuse_write_object_bytes;
static jfieldID app_fuse_buffer;
// NOTE:
@@ -140,6 +141,9 @@
case FUSE_READ:
invoke_handler(fd, req, &AppFuse::handle_fuse_read);
return true;
+ case FUSE_WRITE:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_write);
+ return true;
case FUSE_RELEASE:
invoke_handler(fd, req, &AppFuse::handle_fuse_release);
return true;
@@ -289,6 +293,29 @@
return 0;
}
+ int handle_fuse_write(const fuse_in_header& /* header */,
+ const fuse_write_in* in,
+ FuseResponse<fuse_write_out>* out) {
+ if (in->size > MAX_WRITE) {
+ return -EINVAL;
+ }
+ const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
+ if (it == handles_.end()) {
+ return -EBADF;
+ }
+ const uint64_t offset = in->offset;
+ const uint32_t size = in->size;
+ const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
+ uint32_t written_size;
+ const int result = write_object_bytes(it->second, offset, size, buffer, &written_size);
+ if (result < 0) {
+ return result;
+ }
+ out->prepare_buffer();
+ out->data()->size = written_size;
+ return 0;
+ }
+
int handle_fuse_release(const fuse_in_header& /* header */,
const fuse_release_in* in,
FuseResponse<void>* /* out */) {
@@ -355,6 +382,27 @@
return read_size;
}
+ int write_object_bytes(int inode, uint64_t offset, uint32_t size, const void* buffer,
+ uint32_t* written_size) {
+ ScopedLocalRef<jbyteArray> array(
+ env_,
+ static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
+ {
+ ScopedByteArrayRW bytes(env_, array.get());
+ if (bytes.get() == nullptr) {
+ return -EIO;
+ }
+ memcpy(bytes.get(), buffer, size);
+ }
+ *written_size = env_->CallIntMethod(
+ self_, app_fuse_write_object_bytes, inode, offset, size, array.get());
+ if (env_->ExceptionCheck()) {
+ env_->ExceptionClear();
+ return -EIO;
+ }
+ return 0;
+ }
+
static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
size_t reply_size) {
// Don't send any data for error case.
@@ -469,6 +517,28 @@
return -1;
}
+ app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(IJI[B)I");
+ if (app_fuse_write_object_bytes == nullptr) {
+ ALOGE("Can't find getWriteObjectBytes");
+ return -1;
+ }
+
+ app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
+ if (app_fuse_buffer == nullptr) {
+ ALOGE("Can't find mBuffer");
+ return -1;
+ }
+
+ const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
+ if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
+ return -1;
+ }
+
+ const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
+ if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
+ return -1;
+ }
+
const int result = android::AndroidRuntime::registerNativeMethods(
env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
if (result < 0) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 38435f4..1fd471c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -38,8 +38,12 @@
* Max read amount specified at the FUSE kernel implementation.
* The value is copied from sdcard.c.
*/
+ @UsedByNative("com_android_mtp_AppFuse.cpp")
static final int MAX_READ = 128 * 1024;
+ @UsedByNative("com_android_mtp_AppFuse.cpp")
+ static final int MAX_WRITE = 256 * 1024;
+
private final String mName;
private final Callback mCallback;
@@ -47,7 +51,7 @@
* Buffer for read bytes request.
* Don't use the buffer from the out of AppFuseMessageThread.
*/
- private byte[] mBuffer = new byte[MAX_READ];
+ private byte[] mBuffer = new byte[Math.max(MAX_READ, MAX_WRITE)];
private Thread mMessageThread;
private ParcelFileDescriptor mDeviceFd;
@@ -79,11 +83,22 @@
}
}
- public ParcelFileDescriptor openFile(int i) throws FileNotFoundException {
+ /**
+ * Opens a file on app fuse and returns ParcelFileDescriptor.
+ *
+ * @param i ID for opened file.
+ * @param mode Mode for opening file.
+ * @see ParcelFileDescriptor#MODE_READ_ONLY
+ * @see ParcelFileDescriptor#MODE_WRITE_ONLY
+ */
+ public ParcelFileDescriptor openFile(int i, int mode) throws FileNotFoundException {
+ Preconditions.checkArgument(
+ mode == ParcelFileDescriptor.MODE_READ_ONLY ||
+ mode == ParcelFileDescriptor.MODE_WRITE_ONLY);
return ParcelFileDescriptor.open(new File(
getMountPoint(),
Integer.toString(i)),
- ParcelFileDescriptor.MODE_READ_ONLY);
+ mode);
}
File getMountPoint() {
@@ -100,7 +115,7 @@
long getFileSize(int inode) throws FileNotFoundException;
/**
- * Returns flie bytes for the give inode.
+ * Returns file bytes for the give inode.
* @param inode
* @param offset Offset for file bytes.
* @param size Size for file bytes.
@@ -109,6 +124,17 @@
* @throws IOException
*/
long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
+
+ /**
+ * Handles writing bytes for the give inode.
+ * @param inode
+ * @param offset Offset for file bytes.
+ * @param size Size for file bytes.
+ * @param bytes Buffer to store file bytes.
+ * @return Number of read bytes. Must not be negative.
+ * @throws IOException
+ */
+ int writeObjectBytes(int inode, long offset, int size, byte[] bytes) throws IOException;
}
@UsedByNative("com_android_mtp_AppFuse.cpp")
@@ -138,6 +164,15 @@
}
}
+ @UsedByNative("com_android_mtp_AppFuse.cpp")
+ @WorkerThread
+ private /* unsgined */ int writeObjectBytes(int inode,
+ /* unsigned */ long offset,
+ /* unsigned */ int size,
+ byte[] bytes) throws IOException {
+ return mCallback.writeObjectBytes(inode, offset, size, bytes);
+ }
+
private native boolean native_start_app_fuse_loop(int fd);
private class AppFuseMessageThread extends Thread {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index cf5bee5..4152d1e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -242,7 +242,8 @@
// extension.
if (MtpDeviceRecord.isPartialReadSupported(
device.operationsSupported, fileSize)) {
- return mAppFuse.openFile(Integer.parseInt(documentId));
+ return mAppFuse.openFile(
+ Integer.parseInt(documentId), ParcelFileDescriptor.MODE_READ_ONLY);
} else {
return getPipeManager(identifier).readDocument(mMtpManager, identifier);
}
@@ -606,5 +607,12 @@
public long getFileSize(int inode) throws FileNotFoundException {
return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
}
+
+ @Override
+ public int writeObjectBytes(int inode, long offset, int size, byte[] bytes)
+ throws IOException {
+ // TODO: Implement it.
+ throw new IOException();
+ }
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
index a7f295f..2ded925 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
@@ -22,7 +22,7 @@
/**
* Annotation that shows the method is used by JNI.
*/
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.FIELD})
public @interface UsedByNative {
/**
* JNI file name that uses the method.
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
index c0973bd..3b92506 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -56,7 +56,8 @@
}
});
appFuse.mount(storageManager);
- final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE, ParcelFileDescriptor.MODE_READ_ONLY);
fd.close();
appFuse.close();
}
@@ -67,11 +68,21 @@
final AppFuse appFuse = new AppFuse("test", new TestCallback());
appFuse.mount(storageManager);
try {
- appFuse.openFile(INODE);
+ appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_ONLY);
fail();
- } catch (Throwable t) {
- assertTrue(t instanceof FileNotFoundException);
- }
+ } catch (FileNotFoundException exp) {}
+ appFuse.close();
+ }
+
+ public void testOpenFile_illegalMode() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final AppFuse appFuse = new AppFuse("test", new TestCallback());
+ appFuse.mount(storageManager);
+ try {
+ appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_WRITE);
+ fail();
+ } catch (IllegalArgumentException exp) {}
appFuse.close();
}
@@ -105,7 +116,8 @@
}
});
appFuse.mount(storageManager);
- final ParcelFileDescriptor fd = appFuse.openFile(fileInode);
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ fileInode, ParcelFileDescriptor.MODE_READ_ONLY);
try (final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
final byte[] buffer = new byte[1024];
@@ -115,6 +127,71 @@
appFuse.close();
}
+ public void testWriteFile() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final byte[] resultBytes = new byte[5];
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (inode != INODE) {
+ throw new FileNotFoundException();
+ }
+ return resultBytes.length;
+ }
+
+ @Override
+ public int writeObjectBytes(int inode, long offset, int size, byte[] bytes) {
+ for (int i = 0; i < size; i++) {
+ resultBytes[(int)(offset + i)] = bytes[i];
+ }
+ return size;
+ }
+ });
+ appFuse.mount(storageManager);
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE, ParcelFileDescriptor.MODE_WRITE_ONLY);
+ try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ stream.write('a');
+ stream.write('b');
+ stream.write('c');
+ stream.write('d');
+ stream.write('e');
+ }
+ final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+ assertTrue(Arrays.equals(BYTES, resultBytes));
+ appFuse.close();
+ }
+
+ public void testWriteFile_writeError() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (inode != INODE) {
+ throw new FileNotFoundException();
+ }
+ return 5;
+ }
+ });
+ appFuse.mount(storageManager);
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE, ParcelFileDescriptor.MODE_WRITE_ONLY);
+ try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ stream.write('a');
+ fail();
+ } catch (IOException e) {
+ }
+ appFuse.close();
+ }
+
private static class TestCallback implements AppFuse.Callback {
@Override
public long getFileSize(int inode) throws FileNotFoundException {
@@ -126,5 +203,11 @@
throws IOException {
throw new IOException();
}
+
+ @Override
+ public int writeObjectBytes(int inode, long offset, int size, byte[] bytes)
+ throws IOException {
+ throw new IOException();
+ }
}
}
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
new file mode 100644
index 0000000..89e4aac
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueTo="10dp"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="1.0"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml b/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
new file mode 100644
index 0000000..c73fed6
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="0.0"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index f0bfebe..0f8c77c 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -19,8 +19,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="rtl">
+ android:clipToPadding="false">
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
android:id="@+id/task_list"
android:layout_width="wrap_content"
@@ -29,20 +28,21 @@
android:clipToPadding="false"
android:descendantFocusability="beforeDescendants"
android:layout_marginTop="@dimen/recents_tv_gird_row_top_margin"
- android:focusable="true" />
+ android:focusable="true"
+ android:layoutDirection="rtl" />
+
<View
android:id="@+id/pip_shade"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
- android:background="#76000000"/>
+ android:background="#76000000" />
- <!-- Placeholder view to handle key events for PIP when it's focused.
- Size and positions will be adjusted to comply with the PIP bounds -->
- <View
- android:id="@+id/pip"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone"
- android:focusable="true" />
+ <include
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_marginTop="132dp"
+ layout="@layout/tv_pip_controls" />
+
</com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 59a2bd9..2b3c5df 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -14,28 +14,28 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- The layouts params are calculated in TaskViewHeader.java -->
<com.android.systemui.recents.views.TaskViewHeader
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_view_bar"
android:layout_width="match_parent"
- android:layout_height="@dimen/recents_task_view_header_height"
+ android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal">
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/icon"
android:contentDescription="@string/recents_app_info_button_label"
- android:layout_width="@dimen/recents_task_view_header_icon_width"
- android:layout_height="@dimen/recents_task_view_header_icon_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="16dp"
android:paddingEnd="12dp" />
<LinearLayout
+ android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="56dp"
- android:layout_marginEnd="56dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
@@ -67,21 +67,20 @@
</LinearLayout>
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/move_task"
- android:layout_width="@dimen/recents_task_view_header_button_width"
- android:layout_height="@dimen/recents_task_view_header_button_height"
- android:layout_marginEnd="@dimen/recents_task_view_header_button_width"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
- android:padding="16dp"
+ android:padding="@dimen/recents_task_view_header_button_padding"
android:src="@drawable/star"
android:background="?android:selectableItemBackground"
android:alpha="0"
android:visibility="gone" />
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/dismiss_task"
- android:layout_width="@dimen/recents_task_view_header_button_width"
- android:layout_height="@dimen/recents_task_view_header_button_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
- android:padding="16dp"
+ android:padding="@dimen/recents_task_view_header_button_padding"
android:src="@drawable/recents_dismiss_light"
android:background="?android:selectableItemBackground"
android:alpha="0"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
index 433e69e..cf09b1d 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -13,6 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- The layouts params are calculated in TaskViewHeader.java -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -20,8 +21,8 @@
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/app_icon"
android:contentDescription="@string/recents_app_info_button_label"
- android:layout_width="@dimen/recents_task_view_header_icon_width"
- android:layout_height="@dimen/recents_task_view_header_icon_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:paddingTop="8dp"
android:paddingBottom="8dp"
@@ -32,8 +33,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="56dp"
- android:layout_marginEnd="112dp"
android:textSize="16sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
@@ -44,10 +43,10 @@
android:fadingEdge="horizontal" />
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/app_info"
- android:layout_width="@dimen/recents_task_view_header_button_width"
- android:layout_height="@dimen/recents_task_view_header_button_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
- android:padding="16dp"
+ android:padding="@dimen/recents_task_view_header_button_padding"
android:background="?android:selectableItemBackground"
android:src="@drawable/recents_info_light" />
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
new file mode 100644
index 0000000..2e0c9e7
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.systemui.tv.pip.PipControlsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center">
+
+ <ImageView android:id="@+id/full_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_full_button" />
+
+ <TextView android:id="@+id/full_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_fullscreen"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-50dp"
+ android:orientation="vertical"
+ android:gravity="center">
+
+ <ImageView android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_close_button" />
+
+ <TextView android:id="@+id/close_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_close"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE" />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/play_pause"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-50dp"
+ android:orientation="vertical"
+ android:gravity="center" >
+
+ <ImageView android:id="@+id/play_pause_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_pause_button" />
+
+ <TextView android:id="@+id/play_pause_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_pause"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE" />
+ </LinearLayout>
+</com.android.systemui.tv.pip.PipControlsView>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 1fec49e..c2c83ff 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -26,85 +26,7 @@
android:gravity="top|center_horizontal"
android:clipChildren="false">
- <LinearLayout
- android:layout_width="34dp"
- android:layout_height="wrap_content"
- android:layout_marginEnd="3dp"
- android:orientation="vertical"
- android:gravity="center"
- android:clipChildren="false">
-
- <ImageView android:id="@+id/full_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_full_button" />
-
- <TextView android:id="@+id/full_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_fullscreen"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE"
- android:clipChildren="false" />
- </LinearLayout>
-
- <LinearLayout android:id="@+id/play_pause"
- android:layout_width="34dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="3dp"
- android:layout_marginEnd="3dp"
- android:orientation="vertical"
- android:gravity="center"
- android:clipChildren="false">
-
- <ImageView android:id="@+id/play_pause_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_pause_button" />
-
- <TextView android:id="@+id/play_pause_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_pause"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE"
- android:clipChildren="false" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="34dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="3dp"
- android:orientation="vertical"
- android:gravity="center"
- android:clipChildren="false">
-
- <ImageView android:id="@+id/close_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_close_button" />
-
- <TextView android:id="@+id/close_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_close"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE"
- android:clipChildren="false" />
- </LinearLayout>
+ <include
+ layout="@layout/tv_pip_controls"
+ android:clipChildren="false" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 1ba423b..c5c7e84 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -46,16 +46,17 @@
android:layout_centerHorizontal="true"
android:orientation="horizontal">
<ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="19dp"
+ android:layout_height="19dp"
android:src="@drawable/ic_fullscreen_white_24dp" />
<ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_pause_white_24dp" />
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="19dp"
+ android:layout_height="19dp"
android:src="@drawable/ic_close_white" />
+ <ImageView
+ android:id="@+id/guide_button_play_pause"
+ android:layout_width="19dp"
+ android:layout_height="19dp"
+ android:src="@drawable/ic_pause_white_24dp" />
</LinearLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
new file mode 100644
index 0000000..22b7578
--- /dev/null
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP menu is shown in center. -->
+ <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
+
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP is shown in Recents without focus. -->
+ <string translatable="false" name="pip_recents_bounds">"800 54 1120 234"</string>
+
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP is shown in Recents with focus. -->
+ <string translatable="false" name="pip_recents_focused_bounds">"775 54 1145 262"</string>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5417480..88230bc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -604,16 +604,14 @@
<!-- Recents Views -->
- <!-- The height of a task view bar. -->
+ <!-- The height of a task view bar. This has to be large enough to cover the action bar
+ height in either orientation at this smallest width. -->
<dimen name="recents_task_view_header_height">56dp</dimen>
+ <dimen name="recents_task_view_header_height_tablet_land">64dp</dimen>
- <!-- The size of the icon in the recents task view header. -->
- <dimen name="recents_task_view_header_icon_width">@dimen/recents_task_view_header_height</dimen>
- <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_view_header_height</dimen>
-
- <!-- The size of a button in the recents task view header. -->
- <dimen name="recents_task_view_header_button_width">@dimen/recents_task_view_header_height</dimen>
- <dimen name="recents_task_view_header_button_height">@dimen/recents_task_view_header_height</dimen>
+ <!-- The padding of a button in the recents task view header. -->
+ <dimen name="recents_task_view_header_button_padding">16dp</dimen>
+ <dimen name="recents_task_view_header_button_padding_tablet_land">20dp</dimen>
<!-- The radius of the rounded corners on a task view and its shadow (which can be larger
to create a softer corner effect. -->
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
index c60c245..20cd330 100644
--- a/packages/SystemUI/res/values/integers_tv.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -17,4 +17,5 @@
<integer name="item_scale_anim_duration">150</integer>
<integer name="dismiss_short_duration">200</integer>
<integer name="dismiss_long_duration">400</integer>
-</resources>
\ No newline at end of file
+ <integer name="recents_tv_pip_focus_anim_duration">200</integer>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 3fb3106..1261a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -391,7 +391,7 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- EventBus.getDefault().post(new ConfigurationChangedEvent());
+ EventBus.getDefault().send(new ConfigurationChangedEvent());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 09b76ed..3ff33a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -557,8 +557,13 @@
com.android.internal.R.dimen.navigation_bar_height);
mNavBarWidth = res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width);
- mTaskBarHeight = res.getDimensionPixelSize(
- R.dimen.recents_task_view_header_height);
+ mTaskBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height_tablet_land,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height_tablet_land);
mDummyStackView = new TaskStackView(mContext);
mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
null, false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 8f149d7..ea4888d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -78,6 +78,7 @@
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.tv.RecentsTvImpl;
+import com.android.systemui.recents.model.ThumbnailData;
import java.io.IOException;
import java.util.ArrayList;
@@ -513,44 +514,47 @@
}
/** Returns the top task thumbnail for the given task id */
- public Bitmap getTaskThumbnail(int taskId) {
+ public ThumbnailData getTaskThumbnail(int taskId) {
if (mAm == null) return null;
+ ThumbnailData thumbnailData = new ThumbnailData();
// If we are mocking, then just return a dummy thumbnail
if (RecentsDebugFlags.Static.EnableMockTasks) {
- Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight,
- Bitmap.Config.ARGB_8888);
- thumbnail.eraseColor(0xff333333);
- return thumbnail;
+ thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
+ mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
+ thumbnailData.thumbnail.eraseColor(0xff333333);
+ return thumbnailData;
}
- Bitmap thumbnail = getThumbnail(taskId);
- if (thumbnail != null) {
- thumbnail.setHasAlpha(false);
+ getThumbnail(taskId, thumbnailData);
+ if (thumbnailData.thumbnail != null) {
+ thumbnailData.thumbnail.setHasAlpha(false);
// We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
// left pixel, then assume the whole thumbnail is transparent. Generally, proper
// screenshots are always composed onto a bitmap that has no alpha.
- if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) {
- mBgProtectionCanvas.setBitmap(thumbnail);
- mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(),
- mBgProtectionPaint);
+ if (Color.alpha(thumbnailData.thumbnail.getPixel(0, 0)) == 0) {
+ mBgProtectionCanvas.setBitmap(thumbnailData.thumbnail);
+ mBgProtectionCanvas.drawRect(0, 0, thumbnailData.thumbnail.getWidth(),
+ thumbnailData.thumbnail.getHeight(), mBgProtectionPaint);
mBgProtectionCanvas.setBitmap(null);
Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
}
}
- return thumbnail;
+ return thumbnailData;
}
/**
* Returns a task thumbnail from the activity manager
*/
- public Bitmap getThumbnail(int taskId) {
+ public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {
if (mAm == null) {
- return null;
+ return;
}
ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
- if (taskThumbnail == null) return null;
+ if (taskThumbnail == null) {
+ return;
+ }
Bitmap thumbnail = taskThumbnail.mainThumbnail;
ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
@@ -564,7 +568,8 @@
} catch (IOException e) {
}
}
- return thumbnail;
+ thumbnailDataOut.thumbnail = thumbnail;
+ thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index ff42893..76ca6ca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -246,8 +246,8 @@
if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
if (task.icon == null) {
- task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
- res, true);
+ task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription, res,
+ true);
}
}
if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ee4d95e..dbb692c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -95,7 +95,7 @@
TaskResourceLoadQueue mLoadQueue;
TaskKeyLruCache<Drawable> mIconCache;
- TaskKeyLruCache<Bitmap> mThumbnailCache;
+ TaskKeyLruCache<ThumbnailData> mThumbnailCache;
Bitmap mDefaultThumbnail;
BitmapDrawable mDefaultIcon;
@@ -104,7 +104,7 @@
/** Constructor, creates a new loading thread that loads task resources in the background */
public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
- TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
+ TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<ThumbnailData> thumbnailCache,
Bitmap defaultThumbnail, BitmapDrawable defaultIcon) {
mLoadQueue = loadQueue;
mIconCache = iconCache;
@@ -165,7 +165,7 @@
final Task t = mLoadQueue.nextTask();
if (t != null) {
Drawable cachedIcon = mIconCache.get(t.key);
- Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
+ ThumbnailData cachedThumbnailData = mThumbnailCache.get(t.key);
// Load the icon if it is stale or we haven't cached one yet
if (cachedIcon == null) {
@@ -190,30 +190,32 @@
mIconCache.put(t.key, cachedIcon);
}
// Load the thumbnail if it is stale or we haven't cached one yet
- if (cachedThumbnail == null) {
+ if (cachedThumbnailData == null) {
if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
- cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
+ cachedThumbnailData = ssp.getTaskThumbnail(t.key.id);
}
- if (cachedThumbnail == null) {
- cachedThumbnail = mDefaultThumbnail;
+
+ if (cachedThumbnailData.thumbnail == null) {
+ cachedThumbnailData.thumbnail = mDefaultThumbnail;
}
+
// When svelte, we trim the memory to just the visible thumbnails when
// leaving, so don't thrash the cache as the user scrolls (just load
// them from scratch each time)
if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
- mThumbnailCache.put(t.key, cachedThumbnail);
+ mThumbnailCache.put(t.key, cachedThumbnailData);
}
}
if (!mCancelled) {
// Notify that the task data has changed
final Drawable newIcon = cachedIcon;
- final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
- ? null : cachedThumbnail;
+ final ThumbnailData newThumbnailData = cachedThumbnailData;
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
- t.notifyTaskDataLoaded(newThumbnail, newIcon);
+ t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon,
+ newThumbnailData.thumbnailInfo);
}
});
}
@@ -252,7 +254,7 @@
// package in the cache has been updated, so that we may remove it.
private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
private final TaskKeyLruCache<Drawable> mIconCache;
- private final TaskKeyLruCache<Bitmap> mThumbnailCache;
+ private final TaskKeyLruCache<ThumbnailData> mThumbnailCache;
private final TaskKeyLruCache<String> mActivityLabelCache;
private final TaskKeyLruCache<String> mContentDescriptionCache;
private final TaskResourceLoadQueue mLoadQueue;
@@ -356,9 +358,16 @@
*/
public void loadTaskData(Task t, boolean fetchAndInvalidateThumbnails) {
Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
- Bitmap thumbnail = mDefaultThumbnail;
+ Bitmap thumbnail = null;
+ ActivityManager.TaskThumbnailInfo thumbnailInfo = null;
if (fetchAndInvalidateThumbnails) {
- thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+ ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(t.key);
+ if (thumbnailData != null) {
+ thumbnail = thumbnailData.thumbnail;
+ thumbnailInfo = thumbnailData.thumbnailInfo;
+ }
+ } else {
+ thumbnail = mDefaultThumbnail;
}
// Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
@@ -368,7 +377,8 @@
if (requiresLoad) {
mLoadQueue.addTask(t);
}
- t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon);
+ t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon,
+ thumbnailInfo);
}
/** Releases the task resource data back into the pool. */
@@ -535,19 +545,19 @@
SystemServicesProxy ssp = Recents.getSystemServices();
// Return the cached thumbnail if it exists
- Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
- if (thumbnail != null) {
- return thumbnail;
+ ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(taskKey);
+ if (thumbnailData != null) {
+ return thumbnailData.thumbnail;
}
if (loadIfNotCached) {
RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
// Load the thumbnail from the system
- thumbnail = ssp.getTaskThumbnail(taskKey.id);
- if (thumbnail != null) {
- mThumbnailCache.put(taskKey, thumbnail);
- return thumbnail;
+ thumbnailData = ssp.getTaskThumbnail(taskKey.id);
+ if (thumbnailData.thumbnail != null) {
+ mThumbnailCache.put(taskKey, thumbnailData);
+ return thumbnailData.thumbnail;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 3e858a8..d5d5aa0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -40,7 +40,7 @@
/* Task callbacks */
public interface TaskCallbacks {
/* Notifies when a task has been bound */
- public void onTaskDataLoaded(Task task);
+ public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo);
/* Notifies when a task has been unbound */
public void onTaskDataUnloaded();
/* Notifies when a task's stack id has changed. */
@@ -217,6 +217,7 @@
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.bounds = o.bounds;
+ this.taskDescription = o.taskDescription;
this.isLaunchTarget = o.isLaunchTarget;
this.isStackTask = o.isStackTask;
this.isSystemApp = o.isSystemApp;
@@ -264,12 +265,13 @@
}
/** Notifies the callback listeners that this task has been loaded */
- public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
+ public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon,
+ ActivityManager.TaskThumbnailInfo thumbnailInfo) {
this.icon = applicationIcon;
this.thumbnail = thumbnail;
int callbackCount = mCallbacks.size();
for (int i = 0; i < callbackCount; i++) {
- mCallbacks.get(i).onTaskDataLoaded(this);
+ mCallbacks.get(i).onTaskDataLoaded(this, thumbnailInfo);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
new file mode 100644
index 0000000..d0cdae5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.model;
+
+import android.app.ActivityManager;
+import android.graphics.Bitmap;
+
+/**
+ * Data for a single thumbnail.
+ */
+public class ThumbnailData {
+ public Bitmap thumbnail;
+ public ActivityManager.TaskThumbnailInfo thumbnailInfo;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index d8e82d9..2c34523 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.recents.tv;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
@@ -57,6 +59,7 @@
import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.tv.pip.PipManager;
+import com.android.systemui.tv.pip.PipControlsView;
import java.util.ArrayList;
import java.util.Collections;
@@ -77,8 +80,10 @@
private boolean mIgnoreAltTabRelease;
private RecentsTvView mRecentsView;
- private View mPipView;
+ private PipControlsView mPipControlsView;
private View mPipShadeView;
+ private AnimatorSet mPipControlsViewFadeInAnimator;
+ private AnimatorSet mPipControlsViewFadeOutAnimator;
private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
private FinishRecentsRunnable mFinishLaunchHomeRunnable;
@@ -95,7 +100,9 @@
}
@Override
- public void onShowPipMenu() { }
+ public void onShowPipMenu() {
+ updatePipUI();
+ }
@Override
public void onMoveToFullscreen() { }
@@ -106,7 +113,6 @@
@Override
public void onMediaControllerChanged() { }
};
- private boolean mHasPip;
/**
* A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -253,8 +259,22 @@
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- mPipView = findViewById(R.id.pip);
+ mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+ mPipControlsView.setListener(new PipControlsView.Listener() {
+ @Override
+ public void onClosed() {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+ });
mPipShadeView = findViewById(R.id.pip_shade);
+
+ mPipControlsViewFadeInAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
+ R.anim.tv_pip_controls_fade_in);
+ mPipControlsViewFadeInAnimator.setTarget(mPipControlsView);
+ mPipControlsViewFadeOutAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
+ R.anim.tv_pip_controls_fade_out);
+ mPipControlsViewFadeOutAnimator.setTarget(mPipControlsView);
+
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -265,7 +285,6 @@
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
- mHasPip = false;
updatePipUI();
mPipManager.addListener(mPipListener);
}
@@ -456,37 +475,25 @@
}
private void updatePipUI() {
- if (mHasPip == mPipManager.isPipShown()) {
- return;
- }
- mHasPip = mPipManager.isPipShown();
- if (mHasPip) {
- // Place mPipView at the PIP bounds for fine tuned focus handling.
- Rect pipBounds = mPipManager.getPipBounds();
- LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
- lp.width = pipBounds.width();
- lp.height = pipBounds.height();
- lp.leftMargin = pipBounds.left;
- lp.topMargin = pipBounds.top;
- mPipView.setLayoutParams(lp);
-
- mPipView.setVisibility(View.VISIBLE);
- mPipView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU);
- }
- });
- mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ if (mPipManager.isPipShown()) {
+ mPipControlsView.setAlpha(0);
+ mPipControlsView.setVisibility(View.VISIBLE);
+ mPipShadeView.setVisibility(View.INVISIBLE);
+ mPipControlsView.setOnChildFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mPipManager.onPipViewFocusChangedInRecents(hasFocus);
+ if (hasFocus) {
+ mPipControlsViewFadeInAnimator.start();
+ } else {
+ mPipControlsViewFadeOutAnimator.start();
+ }
mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});
mPipShadeView.setVisibility(View.GONE);
} else {
- mPipView.setVisibility(View.GONE);
+ mPipControlsView.setVisibility(View.GONE);
mPipShadeView.setVisibility(View.GONE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 93c5fc9..83f8b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -963,11 +963,22 @@
}
// Ensure that the new width is at most the smaller display edge size
- Rect displayRect = Recents.getSystemServices().getDisplayRect();
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ Rect displayRect = ssp.getDisplayRect();
int sideMargin = getScaleForExtent(windowRect, displayRect, mBaseSideMargin, mMinMargin,
WIDTH);
- int targetStackWidth = Math.min(taskStackBounds.width() - 2 * sideMargin,
- Math.min(displayRect.width(), displayRect.height()));
+ int targetStackWidth = taskStackBounds.width() - 2 * sideMargin;
+ if (ssp.getDisplayOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ // If we are in landscape, calculate the width of the stack in portrait and ensure that
+ // we are not larger than that size
+ Rect portraitDisplayRect = new Rect(0, 0,
+ Math.min(displayRect.width(), displayRect.height()),
+ Math.max(displayRect.width(), displayRect.height()));
+ int portraitSideMargin = getScaleForExtent(portraitDisplayRect, portraitDisplayRect,
+ mBaseSideMargin, mMinMargin, WIDTH);
+ targetStackWidth = Math.min(targetStackWidth,
+ portraitDisplayRect.width() - 2 * portraitSideMargin);
+ }
taskStackBounds.inset((taskStackBounds.width() - targetStackWidth) / 2, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 107d8d4..0c47b13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -22,6 +22,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
@@ -128,8 +129,6 @@
@ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
- PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
- Paint mDimLayerPaint = new Paint();
float mActionButtonTranslationZ;
@ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
@@ -575,9 +574,9 @@
}
@Override
- public void onTaskDataLoaded(Task task) {
+ public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
// Bind each of the views to the new task data
- mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
+ mThumbnailView.rebindToTask(mTask, thumbnailInfo, mIsDisabledInSafeMode);
mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
mTaskDataLoaded = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index a2e9573..62995a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -34,9 +34,11 @@
import android.os.CountDownTimer;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewDebug;
+import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -153,6 +155,8 @@
// Header drawables
@ViewDebug.ExportedProperty(category="recents")
Rect mTaskViewRect = new Rect();
+ int mHeaderBarHeight;
+ int mHeaderButtonPadding;
int mCornerRadius;
int mHighlightHeight;
@ViewDebug.ExportedProperty(category="recents")
@@ -245,6 +249,57 @@
}
mFocusTimerIndicatorStub = (ViewStub) findViewById(R.id.focus_timer_indicator_stub);
mAppOverlayViewStub = (ViewStub) findViewById(R.id.app_overlay_stub);
+
+ // Update the dimensions of everything in the header. We do this because we need to use
+ // resources for the display, and not the current configuration.
+ Resources res = getResources();
+ mHeaderBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height_tablet_land,
+ R.dimen.recents_task_view_header_height,
+ R.dimen.recents_task_view_header_height_tablet_land);
+ mHeaderButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ R.dimen.recents_task_view_header_button_padding,
+ R.dimen.recents_task_view_header_button_padding,
+ R.dimen.recents_task_view_header_button_padding,
+ R.dimen.recents_task_view_header_button_padding_tablet_land,
+ R.dimen.recents_task_view_header_button_padding,
+ R.dimen.recents_task_view_header_button_padding_tablet_land);
+ updateLayoutParams(mIconView, findViewById(R.id.title_container), mMoveTaskButton,
+ mDismissButton);
+ }
+
+ /**
+ * Programmatically sets the layout params for a header bar layout. This is necessary because
+ * we can't get resources based on the current configuration, but instead need to get them
+ * based on the device configuration.
+ */
+ private void updateLayoutParams(View icon, View title, View secondaryButton, View button) {
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, mHeaderBarHeight, Gravity.TOP);
+ setLayoutParams(lp);
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.START);
+ icon.setLayoutParams(lp);
+ lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
+ lp.leftMargin = mHeaderBarHeight;
+ lp.rightMargin = mMoveTaskButton != null
+ ? 2 * mHeaderBarHeight
+ : mHeaderBarHeight;
+ title.setLayoutParams(lp);
+ if (secondaryButton != null) {
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+ lp.rightMargin = mHeaderBarHeight;
+ secondaryButton.setLayoutParams(lp);
+ secondaryButton.setPadding(mHeaderButtonPadding, mHeaderButtonPadding,
+ mHeaderButtonPadding, mHeaderButtonPadding);
+ }
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+ button.setLayoutParams(lp);
+ button.setPadding(mHeaderButtonPadding, mHeaderButtonPadding, mHeaderButtonPadding,
+ mHeaderButtonPadding);
}
@Override
@@ -579,6 +634,7 @@
mAppInfoView = (ImageView) mAppOverlayView.findViewById(R.id.app_info);
mAppInfoView.setOnClickListener(this);
mAppTitleView = (TextView) mAppOverlayView.findViewById(R.id.app_title);
+ updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
}
// Update the overlay contents for the current app
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index e46708e..e9c09ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -16,7 +16,9 @@
package com.android.systemui.recents.views;
+import android.app.ActivityManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
@@ -34,6 +36,8 @@
import android.view.ViewDebug;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.Task;
@@ -43,17 +47,24 @@
*/
public class TaskViewThumbnail extends View {
-
private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix();
private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix();
private Task mTask;
+ private Rect mDisplayRect = new Rect();
+ private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+
// Drawing
@ViewDebug.ExportedProperty(category="recents")
+ Rect mTaskViewRect = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mThumbnailRect = new Rect();
@ViewDebug.ExportedProperty(category="recents")
- Rect mTaskViewRect = new Rect();
+ float mThumbnailScale;
+ float mFullscreenThumbnailScale;
+ ActivityManager.TaskThumbnailInfo mThumbnailInfo;
+
int mCornerRadius;
@ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
@@ -97,6 +108,8 @@
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
mBgFillPaint.setColor(Color.WHITE);
+ mFullscreenThumbnailScale = context.getResources().getFraction(
+ com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
}
/**
@@ -114,57 +127,75 @@
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ mOrientation = ssp.getDisplayOrientation();
+ mDisplayRect = ssp.getDisplayRect();
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
if (mInvisible) {
return;
}
- int thumbnailHeight = (int) (((float) mTaskViewRect.width() / mThumbnailRect.width()) *
- mThumbnailRect.height());
- if (thumbnailHeight >= mTaskViewRect.height()) {
- // The thumbnail fills the full task view bounds, so just draw it
- canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
- mCornerRadius, mCornerRadius, mDrawPaint);
- } else {
- int count = 0;
- if (thumbnailHeight > 0) {
- // The thumbnail only covers part of the task view bounds, so fill in the
- // non-thumbnail space with the default background color. This is the equivalent of
- // the GL border texture mode.
- count = canvas.save();
+ if (mBitmapShader != null) {
+ int viewWidth = mTaskViewRect.width();
+ int viewHeight = mTaskViewRect.height();
+
+ // We are drawing the thumbnail in the same orientation, so just fit the width
+ int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
+ int thumbnailHeight = (int) (mThumbnailRect.height() * mThumbnailScale);
+
+ if (thumbnailWidth >= viewWidth && thumbnailHeight >= viewHeight) {
+ // Thumbnail fills the full task view bounds, so just draw it
+ canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+ mDrawPaint);
+ } else {
+ // Thumbnail does not fill the full task view bounds, so just draw it and fill the
+ // empty areas with the background color
+ int count = canvas.save();
// Since we only want the top corners to be rounded, draw slightly beyond the
// thumbnail height, but clip to the thumbnail height
- canvas.clipRect(0, 0, mTaskViewRect.width(), thumbnailHeight, Region.Op.REPLACE);
- canvas.drawRoundRect(0, 0, mTaskViewRect.width(), thumbnailHeight + mCornerRadius,
+ canvas.clipRect(0, 0, thumbnailWidth, thumbnailHeight, Region.Op.REPLACE);
+ canvas.drawRoundRect(0, 0,
+ thumbnailWidth + (thumbnailWidth < viewWidth ? mCornerRadius : 0),
+ thumbnailHeight + (thumbnailHeight < viewHeight ? mCornerRadius : 0),
mCornerRadius, mCornerRadius, mDrawPaint);
- }
- // In the remaining space, draw the background color
- canvas.clipRect(0, thumbnailHeight, mTaskViewRect.width(), mTaskViewRect.height(),
- Region.Op.REPLACE);
- canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
- mTaskViewRect.width(), mTaskViewRect.height(), mCornerRadius, mCornerRadius,
- mBgFillPaint);
+ // In the remaining space, draw the background color
+ if (thumbnailWidth < viewWidth) {
+ canvas.clipRect(thumbnailWidth, 0, viewWidth, viewHeight, Region.Op.REPLACE);
+ canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+ viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
+ }
+ if (thumbnailWidth > 0 && thumbnailHeight < viewHeight) {
+ canvas.clipRect(0, thumbnailHeight, viewWidth, viewHeight, Region.Op.REPLACE);
+ canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+ viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
+ }
- if (thumbnailHeight > 0) {
canvas.restoreToCount(count);
}
}
}
/** Sets the thumbnail to a given bitmap. */
- void setThumbnail(Bitmap bm) {
+ void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) {
if (bm != null) {
- mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
- Shader.TileMode.CLAMP);
+ mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mDrawPaint.setShader(mBitmapShader);
mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
+ mThumbnailInfo = thumbnailInfo;
updateThumbnailScale();
} else {
mBitmapShader = null;
mDrawPaint.setShader(null);
mThumbnailRect.setEmpty();
+ mThumbnailInfo = null;
}
}
@@ -210,20 +241,46 @@
* Updates the scale of the bitmap relative to this view.
*/
public void updateThumbnailScale() {
+ mThumbnailScale = 1f;
if (mBitmapShader != null) {
- float thumbnailScale;
- if (!mTask.isFreeformTask() || mTask.bounds == null) {
- // If this is a stack task, or a stack task moved into the freeform workspace, then
- // just scale this thumbnail to fit the width of the view
- thumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width();
+
+ if (mThumbnailInfo != null) {
+ System.out.println(mTask.title + " bounds: " + mThumbnailInfo.taskWidth + "x" + mThumbnailInfo.taskHeight + ", " + mThumbnailInfo.screenOrientation);
+ }
+
+ // We consider this a stack task if it is not freeform (ie. has no bounds) or has been
+ // dragged into the stack from the freeform workspace
+ boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null;
+ if (mTaskViewRect.isEmpty() || mThumbnailInfo == null ||
+ mThumbnailInfo.taskWidth == 0 || mThumbnailInfo.taskHeight == 0) {
+ // If we haven't measured or the thumbnail is invalid, skip the thumbnail drawing
+ // and only draw the background color
+ mThumbnailScale = 0f;
+ } else if (isStackTask) {
+ float invThumbnailScale = 1f / mFullscreenThumbnailScale;
+ if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (mThumbnailInfo.screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
+ // If we are in the same orientation as the screenshot, just scale it to the
+ // width of the task view
+ mThumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width();
+ } else {
+ // Scale the landscape thumbnail up to app size, then scale that to the task
+ // view size to match other portrait screenshots
+ mThumbnailScale = invThumbnailScale *
+ ((float) mTaskViewRect.width() / mDisplayRect.width());
+ }
+ } else {
+ // Otherwise, scale the screenshot to fit 1:1 in the current orientation
+ mThumbnailScale = invThumbnailScale;
+ }
} else {
// Otherwise, if this is a freeform task with task bounds, then scale the thumbnail
// to fit the entire bitmap into the task bounds
- thumbnailScale = Math.min(
+ mThumbnailScale = Math.min(
(float) mTaskViewRect.width() / mThumbnailRect.width(),
(float) mTaskViewRect.height() / mThumbnailRect.height());
}
- mScaleMatrix.setScale(thumbnailScale, thumbnailScale);
+ mScaleMatrix.setScale(mThumbnailScale, mThumbnailScale);
mBitmapShader.setLocalMatrix(mScaleMatrix);
}
if (!mInvisible) {
@@ -261,22 +318,23 @@
}
/** Binds the thumbnail view to the task */
- void rebindToTask(Task t, boolean disabledInSafeMode) {
+ void rebindToTask(Task t, ActivityManager.TaskThumbnailInfo thumbnailInfo,
+ boolean disabledInSafeMode) {
mTask = t;
mDisabledInSafeMode = disabledInSafeMode;
if (t.thumbnail != null) {
- setThumbnail(t.thumbnail);
+ setThumbnail(t.thumbnail, thumbnailInfo);
if (t.colorBackground != 0) {
mBgFillPaint.setColor(t.colorBackground);
}
} else {
- setThumbnail(null);
+ setThumbnail(null, null);
}
}
/** Unbinds the thumbnail view from the task */
void unbindFromTask() {
mTask = null;
- setThumbnail(null);
+ setThumbnail(null, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
new file mode 100644
index 0000000..0e64dcd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv.pip;
+
+import android.app.Activity;
+import android.content.Context;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+
+/**
+ * A view containing PIP controls including fullscreen, close, and media controls.
+ */
+public class PipControlsView extends LinearLayout implements PipManager.Listener {
+ /**
+ * An interface to listen user action.
+ */
+ public interface Listener {
+ /**
+ * Called when an user clicks close PIP button.
+ */
+ void onClosed();
+ }
+
+ private final PipManager mPipManager = PipManager.getInstance();
+ private MediaController mMediaController;
+ private Listener mListener;
+
+ private View mFullButtonView;
+ private View mFullDescriptionView;
+ private View mPlayPauseView;
+ private ImageView mPlayPauseButtonImageView;
+ private TextView mPlayPauseDescriptionTextView;
+ private View mCloseButtonView;
+ private View mCloseDescriptionView;
+
+ private boolean mHasFocus;
+ private OnFocusChangeListener mOnChildFocusChangeListener;
+
+ private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ updatePlayPauseView();
+ }
+ };
+
+ public PipControlsView(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public PipControlsView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+
+ mFullButtonView = findViewById(R.id.full_button);
+ mFullDescriptionView = findViewById(R.id.full_desc);
+ mFullButtonView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPipManager.movePipToFullscreen();
+ }
+ });
+ mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ onChildViewFocusChanged();
+ }
+ });
+
+ mPlayPauseView = findViewById(R.id.play_pause);
+ mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
+ mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
+ mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+ return;
+ }
+ long actions = mMediaController.getPlaybackState().getActions();
+ int state = mMediaController.getPlaybackState().getState();
+ if (mPipManager.getPlaybackState() == PLAYBACK_STATE_PAUSED) {
+ mMediaController.getTransportControls().play();
+ } else if (mPipManager.getPlaybackState() == PLAYBACK_STATE_PLAYING) {
+ mMediaController.getTransportControls().pause();
+ }
+ // View will be updated later in {@link mMediaControllerCallback}
+ }
+ });
+ mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPlayPauseDescriptionTextView.setVisibility(
+ hasFocus ? View.VISIBLE : View.INVISIBLE);
+ onChildViewFocusChanged();
+ }
+ });
+
+ mCloseButtonView = findViewById(R.id.close_button);
+ mCloseDescriptionView = findViewById(R.id.close_desc);
+ mCloseButtonView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPipManager.closePip();
+ mListener.onClosed();
+ }
+ });
+ mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ onChildViewFocusChanged();
+ }
+ });
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ updateMediaController();
+ mPipManager.addListener(this);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mPipManager.removeListener(this);
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ }
+
+ private void updateMediaController() {
+ MediaController newController = mPipManager.getMediaController();
+ if (mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ }
+ updatePlayPauseView();
+ }
+
+ private void updatePlayPauseView() {
+ int state = mPipManager.getPlaybackState();
+ if (state == PLAYBACK_STATE_UNAVAILABLE) {
+ mPlayPauseView.setVisibility(View.GONE);
+ } else {
+ mPlayPauseView.setVisibility(View.VISIBLE);
+ if (state == PLAYBACK_STATE_PLAYING) {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+ } else {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+ }
+ }
+ }
+
+ /**
+ * Sets a listener to be invoked when {@link android.view.View.hasFocus()} is changed.
+ */
+ public void setOnChildFocusChangeListener(OnFocusChangeListener listener) {
+ mOnChildFocusChangeListener = listener;
+ }
+
+ private void onChildViewFocusChanged() {
+ // At this moment, hasFocus() returns true although there's no focused child.
+ boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
+ || (mPlayPauseButtonImageView != null && mPlayPauseButtonImageView.isFocused())
+ || (mCloseButtonView != null && mCloseButtonView.isFocused());
+ if (mHasFocus != hasFocus) {
+ mHasFocus = hasFocus;
+ if (mOnChildFocusChangeListener != null) {
+ mOnChildFocusChangeListener.onFocusChange(getFocusedChild(), mHasFocus);
+ }
+ }
+ }
+
+ /**
+ * Sets the {@link Listener} to listen user actions.
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onPipEntered() { }
+
+ @Override
+ public void onPipActivityClosed() { }
+
+ @Override
+ public void onShowPipMenu() { }
+
+ @Override
+ public void onMoveToFullscreen() { }
+
+ @Override
+ public void onMediaControllerChanged() {
+ updateMediaController();
+ }
+
+ @Override
+ public void onPipResizeAboutToStart() { }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index acb1a7f..68e0883 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -30,6 +30,7 @@
import android.graphics.Rect;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
@@ -37,6 +38,7 @@
import android.util.Log;
import com.android.systemui.Prefs;
+import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
@@ -70,12 +72,23 @@
public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH = 0x2;
+ /**
+ * PIPed activity is playing a media and it can be paused.
+ */
+ static final int PLAYBACK_STATE_PLAYING = 0;
+ /**
+ * PIPed activity has a paused media and it can be played.
+ */
+ static final int PLAYBACK_STATE_PAUSED = 1;
+ /**
+ * Users are unable to control PIPed activity's media playback.
+ */
+ static final int PLAYBACK_STATE_UNAVAILABLE = 2;
+
private static final int CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS = 3000;
private int mSuspendPipResizingReason;
- private static final float SCALE_FACTOR = 1.1f;
-
private Context mContext;
private IActivityManager mActivityManager;
private MediaSessionManager mMediaSessionManager;
@@ -87,6 +100,7 @@
private Rect mMenuModePipBounds;
private Rect mRecentsPipBounds;
private Rect mRecentsFocusedPipBounds;
+ private int mRecentsFocusChangedAnimationDurationMs;
private boolean mInitialized;
private int mPipTaskId = TASK_ID_NO_PIP;
private ComponentName mPipComponentName;
@@ -148,15 +162,13 @@
mPipBounds = Rect.unflattenFromString(res.getString(
com.android.internal.R.string.config_defaultPictureInPictureBounds));
mMenuModePipBounds = Rect.unflattenFromString(res.getString(
- com.android.internal.R.string.config_centeredPictureInPictureBounds));
+ R.string.pip_menu_bounds));
mRecentsPipBounds = Rect.unflattenFromString(res.getString(
- com.android.internal.R.string.config_pictureInPictureBoundsInRecents));
- float scaleBy = (SCALE_FACTOR - 1.0f) / 2;
- mRecentsFocusedPipBounds = new Rect(
- (int) (mRecentsPipBounds.left - scaleBy * mRecentsPipBounds.width()),
- (int) (mRecentsPipBounds.top - scaleBy * mRecentsPipBounds.height()),
- (int) (mRecentsPipBounds.right + scaleBy * mRecentsPipBounds.width()),
- (int) (mRecentsPipBounds.bottom + scaleBy * mRecentsPipBounds.height()));
+ R.string.pip_recents_bounds));
+ mRecentsFocusedPipBounds = Rect.unflattenFromString(res.getString(
+ R.string.pip_recents_focused_bounds));
+ mRecentsFocusChangedAnimationDurationMs = res.getInteger(
+ R.integer.recents_tv_pip_focus_anim_duration);
mActivityManager = ActivityManagerNative.getDefault();
SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
@@ -279,6 +291,7 @@
mSuspendPipResizingReason);
return;
}
+ int animationDurationMs = -1;
switch (mState) {
case STATE_NO_PIP:
mCurrentPipBounds = null;
@@ -288,6 +301,10 @@
break;
case STATE_PIP_OVERLAY:
if (mIsRecentsShown) {
+ if (mCurrentPipBounds == mRecentsFocusedPipBounds
+ || mCurrentPipBounds == mRecentsFocusedPipBounds) {
+ animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+ }
if (mIsPipFocusedInRecent) {
mCurrentPipBounds = mRecentsFocusedPipBounds;
} else {
@@ -302,7 +319,8 @@
break;
}
try {
- mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds, true, true, true, -1);
+ mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
+ true, true, true, animationDurationMs);
} catch (RemoteException e) {
Log.e(TAG, "resizeStack failed", e);
}
@@ -364,9 +382,17 @@
}
/**
+ * Returns {@code true} if the PIP view in
+ * {@link com.android.systemui.recents.tv.RecentsTvActivity} is focused in Recents.
+ * This API is valid only when {@link isRecentsShown()} returns {@code true}.
+ */
+ boolean isPipViewFocusdInRecents() {
+ return mIsPipFocusedInRecent;
+ }
+
+ /**
* Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
- * stack to the centered PIP bound {@link com.android.internal.R.string
- * .config_centeredPictureInPictureBounds}.
+ * stack to the centered PIP bound {@link R.config_centeredPictureInPictureBounds}.
*/
private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu()");
@@ -478,6 +504,32 @@
return mPipMediaController;
}
+ /**
+ * Returns the PIPed activity's playback state.
+ * This returns one of {@link PLAYBACK_STATE_PLAYING}, {@link PLAYBACK_STATE_PAUSED},
+ * or {@link PLAYBACK_STATE_UNAVAILABLE}.
+ */
+ int getPlaybackState() {
+ if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
+ return PLAYBACK_STATE_UNAVAILABLE;
+ }
+ int state = mPipMediaController.getPlaybackState().getState();
+ boolean isPlaying = (state == PlaybackState.STATE_BUFFERING
+ || state == PlaybackState.STATE_CONNECTING
+ || state == PlaybackState.STATE_PLAYING
+ || state == PlaybackState.STATE_FAST_FORWARDING
+ || state == PlaybackState.STATE_REWINDING
+ || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS
+ || state == PlaybackState.STATE_SKIPPING_TO_NEXT);
+ long actions = mPipMediaController.getPlaybackState().getActions();
+ if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
+ return PLAYBACK_STATE_PAUSED;
+ } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
+ return PLAYBACK_STATE_PLAYING;
+ }
+ return PLAYBACK_STATE_UNAVAILABLE;
+ }
+
TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
public void onTaskStackChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index b8b837a..ea9275f 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -17,12 +17,7 @@
package com.android.systemui.tv.pip;
import android.app.Activity;
-import android.media.session.MediaController;
-import android.media.session.PlaybackState;
import android.os.Bundle;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -31,8 +26,6 @@
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-import static android.media.session.PlaybackState.ACTION_PAUSE;
-import static android.media.session.PlaybackState.ACTION_PLAY;
/**
* Activity to show the PIP menu to control PIP.
@@ -41,131 +34,17 @@
private static final String TAG = "PipMenuActivity";
private final PipManager mPipManager = PipManager.getInstance();
- private MediaController mMediaController;
- private View mFullButtonView;
- private View mFullDescriptionView;
- private View mPlayPauseView;
- private ImageView mPlayPauseButtonImageView;
- private TextView mPlayPauseDescriptionTextView;
- private View mCloseButtonView;
- private View mCloseDescriptionView;
+ private PipControlsView mPipControlsView;
private boolean mPipMovedToFullscreen;
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- updatePlayPauseView(state);
- }
- };
-
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- mFullButtonView = findViewById(R.id.full_button);
- mFullDescriptionView = findViewById(R.id.full_desc);
- mFullButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPipManager.movePipToFullscreen();
- mPipMovedToFullscreen = true;
- finish();
- }
- });
- mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- }
- });
- mPlayPauseView = findViewById(R.id.play_pause);
- mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
- mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
- mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mMediaController == null || mMediaController.getPlaybackState() == null) {
- return;
- }
- long actions = mMediaController.getPlaybackState().getActions();
- int state = mMediaController.getPlaybackState().getState();
- if (((actions & ACTION_PLAY) != 0) && !isPlaying(state)) {
- mMediaController.getTransportControls().play();
- } else if ((actions & ACTION_PAUSE) != 0 && isPlaying(state)) {
- mMediaController.getTransportControls().pause();
- }
- // View will be updated later in {@link mMediaControllerCallback}
- }
- });
- mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mPlayPauseDescriptionTextView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- }
- });
-
- mCloseButtonView = findViewById(R.id.close_button);
- mCloseDescriptionView = findViewById(R.id.close_desc);
- mCloseButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPipManager.closePip();
- finish();
- }
- });
- mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- }
- });
- updateMediaController();
- }
-
- private void updateMediaController() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
- return;
- }
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaControllerCallback);
- }
- mMediaController = newController;
- if (mMediaController != null) {
- mMediaController.registerCallback(mMediaControllerCallback);
- updatePlayPauseView(mMediaController.getPlaybackState());
- } else {
- updatePlayPauseView(null);
- }
- }
-
- private void updatePlayPauseView(PlaybackState playbackState) {
- if (playbackState != null
- && (playbackState.getActions() & (ACTION_PLAY | ACTION_PAUSE)) != 0) {
- mPlayPauseView.setVisibility(View.VISIBLE);
- if (isPlaying(playbackState.getState())) {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
- } else {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_play);
- }
- } else {
- mPlayPauseView.setVisibility(View.GONE);
- }
- }
-
- private boolean isPlaying(int state) {
- return state == PlaybackState.STATE_BUFFERING
- || state == PlaybackState.STATE_CONNECTING
- || state == PlaybackState.STATE_PLAYING
- || state == PlaybackState.STATE_FAST_FORWARDING
- || state == PlaybackState.STATE_REWINDING
- || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS
- || state == PlaybackState.STATE_SKIPPING_TO_NEXT;
+ mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
}
private void restorePipAndFinish() {
@@ -184,9 +63,6 @@
@Override
protected void onDestroy() {
super.onDestroy();
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaControllerCallback);
- }
mPipManager.removeListener(this);
mPipManager.resumePipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
@@ -210,13 +86,12 @@
@Override
public void onMoveToFullscreen() {
+ mPipMovedToFullscreen = true;
finish();
}
@Override
- public void onMediaControllerChanged() {
- updateMediaController();
- }
+ public void onMediaControllerChanged() { }
@Override
public void onPipResizeAboutToStart() {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 1de321d..12cb4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
+import android.widget.ImageView;
import com.android.systemui.R;
@@ -46,9 +47,10 @@
private final Handler mHandler = new Handler();
private View mGuideOverlayView;
private View mGuideButtonsView;
+ private ImageView mGuideButtonPlayPauseImageView;
private final Runnable mHideGuideOverlayRunnable = new Runnable() {
public void run() {
- mGuideOverlayView.setVisibility(View.INVISIBLE);
+ mGuideOverlayView.setVisibility(View.GONE);
}
};
@@ -71,6 +73,7 @@
setContentView(R.layout.tv_pip_overlay);
mGuideOverlayView = findViewById(R.id.guide_overlay);
mGuideButtonsView = findViewById(R.id.guide_buttons);
+ mGuideButtonPlayPauseImageView = (ImageView) findViewById(R.id.guide_button_play_pause);
mPipManager.addListener(this);
sPipOverlayActivity = this;
@@ -80,12 +83,17 @@
protected void onResume() {
super.onResume();
// TODO: Implement animation for this
- if (!mPipManager.isRecentsShown()) {
- mGuideOverlayView.setVisibility(View.VISIBLE);
- mGuideButtonsView.setVisibility(View.INVISIBLE);
+ if (mPipManager.isRecentsShown()) {
+ mGuideOverlayView.setVisibility(View.GONE);
+ if (mPipManager.isPipViewFocusdInRecents()) {
+ mGuideButtonsView.setVisibility(View.GONE);
+ } else {
+ mGuideButtonsView.setVisibility(View.VISIBLE);
+ updateGuideButtonsView();
+ }
} else {
- mGuideOverlayView.setVisibility(View.INVISIBLE);
- mGuideButtonsView.setVisibility(View.VISIBLE);
+ mGuideOverlayView.setVisibility(View.VISIBLE);
+ mGuideButtonsView.setVisibility(View.GONE);
}
mHandler.removeCallbacks(mHideGuideOverlayRunnable);
mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
@@ -134,11 +142,30 @@
}
@Override
- public void onMediaControllerChanged() { }
+ public void onMediaControllerChanged() {
+ updateGuideButtonsView();
+ }
@Override
public void finish() {
sPipOverlayActivity = null;
super.finish();
}
+
+ private void updateGuideButtonsView() {
+ switch (mPipManager.getPlaybackState()) {
+ case PipManager.PLAYBACK_STATE_PLAYING:
+ mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
+ mGuideButtonPlayPauseImageView.setImageResource(R.drawable.ic_pause_white_24dp);
+ break;
+ case PipManager.PLAYBACK_STATE_PAUSED:
+ mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
+ mGuideButtonPlayPauseImageView.setImageResource(
+ R.drawable.ic_play_arrow_white_24dp);
+ break;
+ case PipManager.PLAYBACK_STATE_UNAVAILABLE:
+ mGuideButtonPlayPauseImageView.setVisibility(View.GONE);
+ break;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b1398f1..d88ddfd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,6 +71,7 @@
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
+import android.net.metrics.ConnectivityServiceChangeEvent;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -4511,6 +4512,7 @@
private void makeDefault(NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
+ ConnectivityServiceChangeEvent.logEvent(newNetwork.network.netId);
setupDataActivityTracking(newNetwork);
try {
mNetd.setDefaultNetId(newNetwork.network.netId);
@@ -5141,5 +5143,4 @@
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
return new NetworkMonitor(context, handler, nai, defaultRequest);
}
-
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fa0b5dc..1abb5ff 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -526,6 +526,7 @@
// Determines whether to take full screen screenshots
static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
+ public static final float FULLSCREEN_SCREENSHOT_SCALE = 0.6f;
private static native int nativeMigrateToBoost();
private static native int nativeMigrateFromBoost();
@@ -1491,6 +1492,7 @@
/** The dimensions of the thumbnails in the Recents UI. */
int mThumbnailWidth;
int mThumbnailHeight;
+ float mFullscreenThumbnailScale;
final ServiceThread mHandlerThread;
final MainHandler mHandler;
@@ -12590,6 +12592,8 @@
com.android.internal.R.dimen.thumbnail_width);
mThumbnailHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.thumbnail_height);
+ mFullscreenThumbnailScale = res.getFraction(
+ com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString(
com.android.internal.R.string.config_defaultPictureInPictureBounds));
mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index bbc37cd..5cb04c8 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -929,7 +929,7 @@
// use within SystemUI while keeping memory usage low.
if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
w = h = -1;
- scale = 0.5f;
+ scale = mService.mFullscreenThumbnailScale;
}
return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
w, h, scale);
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index f6dc9b9..7cac227 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -60,7 +60,7 @@
private long mLastSentEventTimeMillis = System.currentTimeMillis();
private final void enforceConnectivityInternalPermission() {
- getContext().enforceCallingPermission(
+ getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CONNECTIVITY_INTERNAL,
"MetricsLoggerService");
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index bce7733..bbb162e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -34,6 +34,8 @@
import android.net.ProxyInfo;
import android.net.TrafficStats;
import android.net.Uri;
+import android.net.metrics.CaptivePortalCheckResultEvent;
+import android.net.metrics.CaptivePortalStateChangeEvent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -297,9 +299,13 @@
transitionTo(mLingeringState);
return HANDLED;
case CMD_NETWORK_CONNECTED:
+ CaptivePortalStateChangeEvent.logEvent(
+ CaptivePortalStateChangeEvent.NETWORK_MONITOR_CONNECTED);
transitionTo(mEvaluatingState);
return HANDLED;
case CMD_NETWORK_DISCONNECTED:
+ CaptivePortalStateChangeEvent.logEvent(
+ CaptivePortalStateChangeEvent.NETWORK_MONITOR_DISCONNECTED);
if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
mLaunchCaptivePortalAppBroadcastReceiver = null;
@@ -349,6 +355,8 @@
private class ValidatedState extends State {
@Override
public void enter() {
+ CaptivePortalStateChangeEvent.logEvent(
+ CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo));
}
@@ -457,6 +465,8 @@
// will be unresponsive. isCaptivePortal() could be executed on another Thread
// if this is found to cause problems.
int httpResponseCode = isCaptivePortal();
+ CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
+ httpResponseCode);
if (httpResponseCode == 204) {
transitionTo(mValidatedState);
} else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bea300a..2a57d8e 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -48,6 +48,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Debug;
@@ -945,6 +946,8 @@
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = mTmpRect.height();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
+ final int thumbStartX = mTmpRect.left - containingFrame.left;
+ final int thumbStartY = mTmpRect.top - containingFrame.top;
// Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
float scale = 1f;
@@ -956,6 +959,9 @@
a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
containingFrame, surfaceInsets, taskId);
} else {
+ AnimationSet set = new AnimationSet(true);
+
+ // In portrait, we scale to fit the width
mTmpFromClipRect.set(containingFrame);
mTmpToClipRect.set(containingFrame);
@@ -966,26 +972,40 @@
// Exclude insets region from the source clip.
mTmpFromClipRect.inset(contentInsets);
-
- // We scale the width and clip to the top/left square
- scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
-
mNextAppTransitionInsets.set(contentInsets);
- Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
- computePivot(mTmpRect.left - containingFrame.left, scale),
- computePivot(mTmpRect.top - containingFrame.top, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // We scale the width and clip to the top/left square
+ scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
- AnimationSet set = new AnimationSet(true);
- set.addAnimation(clipAnim);
- set.addAnimation(scaleAnim);
- set.addAnimation(translateAnim);
+ Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
+ computePivot(mTmpRect.left - containingFrame.left, scale),
+ computePivot(mTmpRect.top - containingFrame.top, scale));
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+
+ } else {
+ // In landscape, we don't scale at all and only crop
+ mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
+ mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
+
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(thumbStartX, 0,
+ thumbStartY - contentInsets.top, 0);
+
+ set.addAnimation(clipAnim);
+ set.addAnimation(translateAnim);
+ }
+
a = set;
+ a.setZAdjustment(Animation.ZORDER_TOP);
}
break;
}
@@ -1017,6 +1037,7 @@
a = createAspectScaledThumbnailExitFreeformAnimationLocked(
containingFrame, surfaceInsets, taskId);
} else {
+ AnimationSet set = new AnimationSet(true);
mTmpFromClipRect.set(containingFrame);
mTmpToClipRect.set(containingFrame);
@@ -1027,25 +1048,37 @@
// Exclude insets region from the target clip.
mTmpToClipRect.inset(contentInsets);
-
- // We scale the width and clip to the top/left square
- scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
-
mNextAppTransitionInsets.set(contentInsets);
- Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
- computePivot(mTmpRect.left - containingFrame.left, scale),
- computePivot(mTmpRect.top - containingFrame.top, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // We scale the width and clip to the top/left square
+ scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
- AnimationSet set = new AnimationSet(true);
- set.addAnimation(clipAnim);
- set.addAnimation(scaleAnim);
- set.addAnimation(translateAnim);
+ Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
+ computePivot(mTmpRect.left - containingFrame.left, scale),
+ computePivot(mTmpRect.top - containingFrame.top, scale));
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
+
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+
+ } else {
+ // In landscape, we don't scale at all and only crop
+ mTmpToClipRect.bottom = mTmpToClipRect.top + thumbHeightI;
+ mTmpToClipRect.right = mTmpToClipRect.left + thumbWidthI;
+
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(0, thumbStartX, 0,
+ thumbStartY - contentInsets.top);
+
+ set.addAnimation(clipAnim);
+ set.addAnimation(translateAnim);
+ }
a = set;
a.setZAdjustment(Animation.ZORDER_TOP);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 42cc0ed..406dd56 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -30,6 +30,8 @@
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
+import android.net.metrics.IpConnectivityEvent;
+import android.net.metrics.DhcpClientEvent;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
@@ -356,11 +358,15 @@
if (!stopped) {
Log.e(TAG, "Read error", e);
}
+ DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_RECV_ERROR,
+ mIfaceName, e.getMessage());
} catch (DhcpPacket.ParseException e) {
Log.e(TAG, "Can't parse packet: " + e.getMessage());
if (PACKET_DBG) {
Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
}
+ DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_PARSE_ERROR, mIfaceName,
+ e.getMessage());
}
}
if (DBG) Log.d(TAG, "Receive thread stopped");
@@ -457,7 +463,9 @@
abstract class LoggingState extends State {
public void enter() {
- if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
+ String msg = "Entering state " + getName();
+ if (STATE_DBG) Log.d(TAG, msg);
+ DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_STATE_CHANGE, mIfaceName, msg);
}
private String messageName(int what) {
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 5b4fd50..af3175a 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,6 +24,8 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.metrics.IpReachabilityMonitorMessageEvent;
+import android.net.metrics.IpReachabilityMonitorProbeEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
@@ -162,7 +164,7 @@
private boolean mRunning;
/**
- * Make the kernel to perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+ * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
* for the given IP address on the specified interface index.
*
* @return true, if the request was successfully passed to the kernel; false otherwise.
@@ -203,7 +205,8 @@
} catch (ErrnoException | InterruptedIOException | SocketException e) {
Log.d(TAG, "Error " + msgSnippet, e);
}
-
+ IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
+ returnValue);
return returnValue;
}
@@ -400,8 +403,7 @@
return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
}
-
- // TODO: simply the number of objects by making this extend Thread.
+ // TODO: simplify the number of objects by making this extend Thread.
private final class NetlinkSocketObserver implements Runnable {
private NetlinkSocket mSocket;
@@ -519,6 +521,8 @@
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
+ IpReachabilityMonitorMessageEvent.logEvent(maybeGetInterfaceName(mInterfaceIndex),
+ destination.getHostAddress(), msgType, nudState);
final String eventMsg = "NeighborEvent{"
+ "elapsedMs=" + whenMs + ", "
+ destination.getHostAddress() + ", "
@@ -549,4 +553,11 @@
}
}
}
+
+ private String maybeGetInterfaceName(int index) {
+ if (index == mInterfaceIndex) {
+ return mInterfaceName;
+ }
+ return "ifindex-" + index;
+ }
}
diff --git a/services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java b/services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java
new file mode 100644
index 0000000..163f7e40
--- /dev/null
+++ b/services/net/java/android/net/metrics/CaptivePortalCheckResultEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CaptivePortalCheckResultEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "CaptivePortalCheckResultEvent";
+
+ private int mNetId;
+ private int mResult;
+
+ public CaptivePortalCheckResultEvent(int netId, int result) {
+ mNetId = netId;
+ mResult = result;
+ }
+
+ public CaptivePortalCheckResultEvent(Parcel in) {
+ mNetId = in.readInt();
+ mResult = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mNetId);
+ out.writeInt(mResult);
+ }
+
+ public static final Parcelable.Creator<CaptivePortalCheckResultEvent> CREATOR
+ = new Parcelable.Creator<CaptivePortalCheckResultEvent>() {
+ public CaptivePortalCheckResultEvent createFromParcel(Parcel in) {
+ return new CaptivePortalCheckResultEvent(in);
+ }
+
+ public CaptivePortalCheckResultEvent[] newArray(int size) {
+ return new CaptivePortalCheckResultEvent[size];
+ }
+ };
+
+ public static void logEvent(int netId, int result) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_NETMON_CHECK_RESULT,
+ new CaptivePortalCheckResultEvent(netId, result));
+ }
+};
diff --git a/services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java
new file mode 100644
index 0000000..d0cc120
--- /dev/null
+++ b/services/net/java/android/net/metrics/CaptivePortalStateChangeEvent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CaptivePortalStateChangeEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "CaptivePortalStateChangeEvent";
+
+ public static final int NETWORK_MONITOR_CONNECTED = 0;
+ public static final int NETWORK_MONITOR_DISCONNECTED = 1;
+ public static final int NETWORK_MONITOR_VALIDATED = 2;
+ private int mState;
+
+ public CaptivePortalStateChangeEvent(int state) {
+ mState = state;
+ }
+
+ public CaptivePortalStateChangeEvent(Parcel in) {
+ mState = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mState);
+ }
+
+ public static final Parcelable.Creator<CaptivePortalStateChangeEvent> CREATOR
+ = new Parcelable.Creator<CaptivePortalStateChangeEvent>() {
+ public CaptivePortalStateChangeEvent createFromParcel(Parcel in) {
+ return new CaptivePortalStateChangeEvent(in);
+ }
+
+ public CaptivePortalStateChangeEvent[] newArray(int size) {
+ return new CaptivePortalStateChangeEvent[size];
+ }
+ };
+
+ public static void logEvent(int state) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_NETMON_STATE_CHANGE,
+ new CaptivePortalStateChangeEvent(state));
+ }
+};
diff --git a/services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java
new file mode 100644
index 0000000..92b376c
--- /dev/null
+++ b/services/net/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "ConnectivityServiceChangeEvent";
+
+ private int mNetId;
+
+ public ConnectivityServiceChangeEvent(int netId) {
+ mNetId = netId;
+ }
+
+ public ConnectivityServiceChangeEvent(Parcel in) {
+ mNetId = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mNetId);
+ }
+
+ public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
+ = new Parcelable.Creator<ConnectivityServiceChangeEvent>() {
+ public ConnectivityServiceChangeEvent createFromParcel(Parcel in) {
+ return new ConnectivityServiceChangeEvent(in);
+ }
+
+ public ConnectivityServiceChangeEvent[] newArray(int size) {
+ return new ConnectivityServiceChangeEvent[size];
+ }
+ };
+
+ public static void logEvent(int netId) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_CONSRV_DEFAULT_NET_CHANGE,
+ new ConnectivityServiceChangeEvent(netId));
+ }
+};
diff --git a/services/net/java/android/net/metrics/DhcpClientEvent.java b/services/net/java/android/net/metrics/DhcpClientEvent.java
new file mode 100644
index 0000000..2c24034
--- /dev/null
+++ b/services/net/java/android/net/metrics/DhcpClientEvent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class DhcpClientEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "DhcpClientEvent";
+
+ private String mIfName;
+ private String mMsg;
+
+ public DhcpClientEvent(String ifName, String msg) {
+ mIfName = ifName;
+ mMsg = msg;
+ }
+
+ public DhcpClientEvent(Parcel in) {
+ mIfName = in.readString();
+ mMsg = in.readString();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ out.writeString(mMsg);
+ }
+
+ public static final Parcelable.Creator<DhcpClientEvent> CREATOR
+ = new Parcelable.Creator<DhcpClientEvent>() {
+ public DhcpClientEvent createFromParcel(Parcel in) {
+ return new DhcpClientEvent(in);
+ }
+
+ public DhcpClientEvent[] newArray(int size) {
+ return new DhcpClientEvent[size];
+ }
+ };
+
+ public static void logEvent(int eventType, String ifName, String msg) {
+ IpConnectivityEvent.logEvent(eventType, new DhcpClientEvent(ifName, msg));
+ }
+};
diff --git a/services/net/java/android/net/metrics/IpConnectivityEvent.java b/services/net/java/android/net/metrics/IpConnectivityEvent.java
new file mode 100644
index 0000000..f277bd0
--- /dev/null
+++ b/services/net/java/android/net/metrics/IpConnectivityEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.net.ConnectivityMetricsLogger;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class IpConnectivityEvent implements Parcelable {
+ // IPRM = IpReachabilityMonitor
+ // DHCP = DhcpClient
+ // NETMON = NetworkMonitorEvent
+ // CONSRV = ConnectivityServiceEvent
+ public static final String TAG = "IpConnectivityEvent";
+ public static final int IPCE_IPRM_BASE = 0*1024;
+ public static final int IPCE_DHCP_BASE = 1*1024;
+ public static final int IPCE_NETMON_BASE = 2*1024;
+ public static final int IPCE_CONSRV_BASE = 3*1024;
+
+ public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
+ public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+ public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
+ public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
+ public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
+ public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3;
+ public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
+ public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
+ public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
+
+ private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ }
+
+ public static void logEvent(int tag, IpConnectivityEvent event) {
+ long timestamp = System.currentTimeMillis();
+ mMetricsLogger.logEvent(timestamp, ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY,
+ tag, event);
+ }
+};
diff --git a/services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
new file mode 100644
index 0000000..a8c18d6
--- /dev/null
+++ b/services/net/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
+ implements Parcelable {
+ public static final String TAG = "IpReachabilityMonitorMessageEvent";
+
+ private String mIfName;
+ private String mDestination;
+ private int mMsgType;
+ private int mNudState;
+
+ public IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
+ int nudState) {
+ mIfName = ifName;
+ mDestination = destination;
+ mMsgType = msgType;
+ mNudState = nudState;
+ }
+
+ public IpReachabilityMonitorMessageEvent(Parcel in) {
+ mIfName = in.readString();
+ mDestination = in.readString();
+ mMsgType = in.readInt();
+ mNudState = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ out.writeString(mDestination);
+ out.writeInt(mMsgType);
+ out.writeInt(mNudState);
+ }
+
+ public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
+ = new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
+ public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
+ return new IpReachabilityMonitorMessageEvent(in);
+ }
+
+ public IpReachabilityMonitorMessageEvent[] newArray(int size) {
+ return new IpReachabilityMonitorMessageEvent[size];
+ }
+ };
+
+ public static void logEvent(String ifName, String destination, int msgType, int nudState) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_MESSAGE_RECEIVED,
+ new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
+ }
+};
diff --git a/services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
new file mode 100644
index 0000000..172cbf8
--- /dev/null
+++ b/services/net/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
+ implements Parcelable {
+ public static final String TAG = "IpReachabilityMonitorProbeEvent";
+
+ private String mIfName;
+ private String mDestination;
+ private boolean mSuccess;
+
+ public IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
+ mIfName = ifName;
+ mDestination = destination;
+ mSuccess = success;
+ }
+
+ public IpReachabilityMonitorProbeEvent(Parcel in) {
+ mIfName = in.readString();
+ mDestination = in.readString();
+ mSuccess = in.readByte() > 0 ? true : false;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ out.writeString(mDestination);
+ out.writeByte((byte)(mSuccess ? 1 : 0));
+ }
+
+ public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
+ = new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
+ public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
+ return new IpReachabilityMonitorProbeEvent(in);
+ }
+
+ public IpReachabilityMonitorProbeEvent[] newArray(int size) {
+ return new IpReachabilityMonitorProbeEvent[size];
+ }
+ };
+
+ public static void logEvent(String ifName, String destination, boolean success) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_PROBE_RESULT,
+ new IpReachabilityMonitorProbeEvent(ifName, destination, success));
+ }
+};
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e26e54b..b4c6e6a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -250,7 +250,7 @@
* in its manifest.
* <p>
* See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
- * {@link Connection#CAPABILITY_IS_EXTERNAL_CALL}.
+ * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
*/
public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
@@ -296,13 +296,13 @@
* Consider, for example, a scenario where a user has two phones with the same phone number.
* When a user places a call on one device, the telephony stack can represent that call on
* the other device by adding it to the {@link ConnectionService} with the
- * {@link Connection#CAPABILITY_IS_EXTERNAL_CALL} capability set.
+ * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
* <p>
* An {@link InCallService} will only see calls with this property if it has the
* {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
* in its manifest.
* <p>
- * See {@link Connection#CAPABILITY_IS_EXTERNAL_CALL}.
+ * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
*/
public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
@@ -686,7 +686,7 @@
sb.append(", caps: ");
sb.append(capabilitiesToString(mCallCapabilities));
sb.append(", props: ");
- sb.append(mCallProperties);
+ sb.append(propertiesToString(mCallProperties));
sb.append("]");
return sb.toString();
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 00e07af..06851ee 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -53,6 +53,8 @@
public void onDestroyed(Conference conference) {}
public void onConnectionCapabilitiesChanged(
Conference conference, int connectionCapabilities) {}
+ public void onConnectionPropertiesChanged(
+ Conference conference, int connectionProperties) {}
public void onVideoStateChanged(Conference c, int videoState) { }
public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
@@ -74,6 +76,7 @@
private int mState = Connection.STATE_NEW;
private DisconnectCause mDisconnectCause;
private int mConnectionCapabilities;
+ private int mConnectionProperties;
private String mDisconnectMessage;
private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
@@ -156,6 +159,16 @@
}
/**
+ * Returns the properties of the conference. See {@code PROPERTY_*} constants in class
+ * {@link Connection} for valid values.
+ *
+ * @return A bitmask of the properties of the conference call.
+ */
+ public final int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
+ /**
* Whether the given capabilities support the specified capability.
*
* @param capabilities A capability bit field.
@@ -364,7 +377,7 @@
* Sets the capabilities of a conference. See {@code CAPABILITY_*} constants of class
* {@link Connection} for valid values.
*
- * @param connectionCapabilities A bitmask of the {@code PhoneCapabilities} of the conference call.
+ * @param connectionCapabilities A bitmask of the {@code Capabilities} of the conference call.
*/
public final void setConnectionCapabilities(int connectionCapabilities) {
if (connectionCapabilities != mConnectionCapabilities) {
@@ -377,6 +390,22 @@
}
/**
+ * Sets the properties of a conference. See {@code PROPERTY_*} constants of class
+ * {@link Connection} for valid values.
+ *
+ * @param connectionProperties A bitmask of the {@code Properties} of the conference call.
+ */
+ public final void setConnectionProperties(int connectionProperties) {
+ if (connectionProperties != mConnectionProperties) {
+ mConnectionProperties = connectionProperties;
+
+ for (Listener l : mListeners) {
+ l.onConnectionPropertiesChanged(this, mConnectionProperties);
+ }
+ }
+ }
+
+ /**
* Adds the specified connection as a child of this conference.
*
* @param connection The connection to add.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3ea1c6a..310c957 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -98,7 +98,7 @@
* The state of an external connection which is in the process of being pulled from a remote
* device to the local device.
* <p>
- * A connection can only be in this state if the {@link #CAPABILITY_IS_EXTERNAL_CALL} and
+ * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
* {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
*/
public static final int STATE_PULLING_CALL = 7;
@@ -194,31 +194,28 @@
public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
/**
- * Whether the call is a generic conference, where we do not know the precise state of
- * participants in the conference (eg. on CDMA).
- *
+ * Un-used.
* @hide
*/
- public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
+ public static final int CAPABILITY_UNUSED_2 = 0x00004000;
/**
- * Connection is using high definition audio.
+ * Un-used.
* @hide
*/
- public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
+ public static final int CAPABILITY_UNUSED_3 = 0x00008000;
/**
- * Connection is using WIFI.
+ * Un-used.
* @hide
*/
- public static final int CAPABILITY_WIFI = 0x00010000;
+ public static final int CAPABILITY_UNUSED_4 = 0x00010000;
/**
- * Indicates that the current device callback number should be shown.
- *
+ * Un-used.
* @hide
*/
- public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
+ public static final int CAPABILITY_UNUSED_5 = 0x00020000;
/**
* Speed up audio setup for MT call.
@@ -281,32 +278,64 @@
public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
/**
+ * When set for an external connection, indicates that this {@code Connection} can be pulled
+ * from a remote device to the current device.
+ * <p>
+ * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
+ * is set.
+ */
+ public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
+
+ //**********************************************************************************************
+ // Next CAPABILITY value: 0x02000000
+ //**********************************************************************************************
+
+ /**
+ * Indicates that the current device callback number should be shown.
+ *
+ * @hide
+ */
+ public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
+
+ /**
+ * Whether the call is a generic conference, where we do not know the precise state of
+ * participants in the conference (eg. on CDMA).
+ *
+ * @hide
+ */
+ public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
+
+ /**
+ * Connection is using high definition audio.
+ * @hide
+ */
+ public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
+
+ /**
+ * Connection is using WIFI.
+ * @hide
+ */
+ public static final int PROPERTY_WIFI = 1<<3;
+
+ /**
* When set, indicates that the {@code Connection} does not actually exist locally for the
* {@link ConnectionService}.
* <p>
* Consider, for example, a scenario where a user has two devices with the same phone number.
* When a user places a call on one devices, the telephony stack can represent that call on the
* other device by adding is to the {@link ConnectionService} with the
- * {@code CAPABILITY_IS_EXTERNAL_CALL} capability set.
+ * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set.
* <p>
* An {@link ConnectionService} should not assume that all {@link InCallService}s will handle
* external connections. Only those {@link InCallService}s which have the
* {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
* manifest will see external connections.
*/
- public static final int CAPABILITY_IS_EXTERNAL_CALL = 0x01000000;
+ public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
- /**
- * When set for an external connection, indicates that this {@code Connection} can be pulled
- * from a remote device to the current device.
- * <p>
- * Should only be set on a {@code Connection} where {@link #CAPABILITY_IS_EXTERNAL_CALL}
- * is set.
- */
- public static final int CAPABILITY_CAN_PULL_CALL = 0x02000000;
//**********************************************************************************************
- // Next CAPABILITY value: 0x04000000
+ // Next PROPERTY value: 1<<5
//**********************************************************************************************
/**
@@ -454,18 +483,6 @@
if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
}
- if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
- builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
- }
- if (can(capabilities, CAPABILITY_WIFI)) {
- builder.append(" CAPABILITY_WIFI");
- }
- if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
- builder.append(" CAPABILITY_GENERIC_CONFERENCE");
- }
- if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
- builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
- }
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
@@ -481,9 +498,6 @@
if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
}
- if (can(capabilities, CAPABILITY_IS_EXTERNAL_CALL)) {
- builder.append(" CAPABILITY_IS_EXTERNAL_CALL");
- }
if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
builder.append(" CAPABILITY_CAN_PULL_CALL");
}
@@ -492,6 +506,34 @@
return builder.toString();
}
+ public static String propertiesToString(int properties) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[Properties:");
+
+ if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
+ builder.append(" PROPERTY_SHOW_CALLBACK_NUMBER");
+ }
+
+ if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
+ builder.append(" PROPERTY_HIGH_DEF_AUDIO");
+ }
+
+ if (can(properties, PROPERTY_WIFI)) {
+ builder.append(" PROPERTY_WIFI");
+ }
+
+ if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
+ builder.append(" PROPERTY_GENERIC_CONFERENCE");
+ }
+
+ if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
+ builder.append(" PROPERTY_IS_EXTERNAL_CALL");
+ }
+
+ builder.append("]");
+ return builder.toString();
+ }
+
/** @hide */
public abstract static class Listener {
public void onStateChanged(Connection c, int state) {}
@@ -505,6 +547,7 @@
public void onRingbackRequested(Connection c, boolean ringback) {}
public void onDestroyed(Connection c) {}
public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
+ public void onConnectionPropertiesChanged(Connection c, int properties) {}
public void onVideoProviderChanged(
Connection c, VideoProvider videoProvider) {}
public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
@@ -1175,6 +1218,7 @@
private int mCallerDisplayNamePresentation;
private boolean mRingbackRequested = false;
private int mConnectionCapabilities;
+ private int mConnectionProperties;
private VideoProvider mVideoProvider;
private boolean mAudioModeIsVoip;
private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
@@ -1439,6 +1483,13 @@
}
/**
+ * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
+ */
+ public final int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
+ /**
* Sets the value of the {@link #getAddress()} property.
*
* @param address The new address.
@@ -1635,6 +1686,21 @@
}
/**
+ * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
+ *
+ * @param connectionProperties The new connection properties.
+ */
+ public final void setConnectionProperties(int connectionProperties) {
+ checkImmutable();
+ if (mConnectionProperties != connectionProperties) {
+ mConnectionProperties = connectionProperties;
+ for (Listener l : mListeners) {
+ l.onConnectionPropertiesChanged(this, mConnectionProperties);
+ }
+ }
+ }
+
+ /**
* Tears down the Connection object.
*/
public final void destroy() {
@@ -2042,10 +2108,10 @@
* The {@link InCallService} issues a request to pull an external call to the local device via
* {@link Call#pullExternalCall()}.
* <p>
- * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL} and
- * {@link Connection#CAPABILITY_IS_EXTERNAL_CALL} capability bits must be set.
+ * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL}
+ * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
* <p>
- * For more information on external calls, see {@link Connection#CAPABILITY_IS_EXTERNAL_CALL}.
+ * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
*/
public void onPullExternalCall() {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index e092095..4cab7f0 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -495,6 +495,16 @@
}
@Override
+ public void onConnectionPropertiesChanged(
+ Conference conference,
+ int connectionProperties) {
+ String id = mIdByConference.get(conference);
+ Log.d(this, "call capabilities: conference: %s",
+ Connection.propertiesToString(connectionProperties));
+ mAdapter.setConnectionProperties(id, connectionProperties);
+ }
+
+ @Override
public void onVideoStateChanged(Conference c, int videoState) {
String id = mIdByConference.get(c);
Log.d(this, "onVideoStateChanged set video state %d", videoState);
@@ -623,6 +633,14 @@
}
@Override
+ public void onConnectionPropertiesChanged(Connection c, int properties) {
+ String id = mIdByConnection.get(c);
+ Log.d(this, "properties: parcelableconnection: %s",
+ Connection.propertiesToString(properties));
+ mAdapter.setConnectionProperties(id, properties);
+ }
+
+ @Override
public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
String id = mIdByConnection.get(c);
Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
@@ -740,10 +758,11 @@
Uri address = connection.getAddress();
String number = address == null ? "null" : address.getSchemeSpecificPart();
- Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s",
+ Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
Connection.toLogSafePhoneNumber(number),
Connection.stateToString(connection.getState()),
- Connection.capabilitiesToString(connection.getConnectionCapabilities()));
+ Connection.capabilitiesToString(connection.getConnectionCapabilities()),
+ Connection.propertiesToString(connection.getConnectionProperties()));
Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
mAdapter.handleCreateConnectionComplete(
@@ -753,6 +772,7 @@
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
+ connection.getConnectionProperties(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
@@ -1110,6 +1130,7 @@
conference.getPhoneAccountHandle(),
conference.getState(),
conference.getConnectionCapabilities(),
+ conference.getConnectionProperties(),
connectionIds,
conference.getVideoProvider() == null ?
null : conference.getVideoProvider().getInterface(),
@@ -1150,6 +1171,7 @@
phoneAccountHandle,
connection.getState(),
connection.getConnectionCapabilities(),
+ connection.getConnectionProperties(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 81e4c22..c8cd3c0 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -196,6 +196,15 @@
}
}
+ void setConnectionProperties(String callId, int properties) {
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.setConnectionProperties(callId, properties);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
/**
* Indicates whether or not the specified call is currently conferenced into the specified
* conference call.
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 3e46557..bf28feb 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -64,6 +64,7 @@
private static final int MSG_PUT_EXTRAS = 24;
private static final int MSG_REMOVE_EXTRAS = 25;
private static final int MSG_ON_CONNECTION_EVENT = 26;
+ private static final int MSG_SET_CONNECTION_PROPERTIES = 27;
private final IConnectionServiceAdapter mDelegate;
@@ -118,6 +119,9 @@
case MSG_SET_CONNECTION_CAPABILITIES:
mDelegate.setConnectionCapabilities((String) msg.obj, msg.arg1);
break;
+ case MSG_SET_CONNECTION_PROPERTIES:
+ mDelegate.setConnectionProperties((String) msg.obj, msg.arg1);
+ break;
case MSG_SET_IS_CONFERENCED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
@@ -322,6 +326,13 @@
}
@Override
+ public void setConnectionProperties(String connectionId, int connectionProperties) {
+ mHandler.obtainMessage(
+ MSG_SET_CONNECTION_PROPERTIES, connectionProperties, 0, connectionId)
+ .sendToTarget();
+ }
+
+ @Override
public void setConferenceMergeFailed(String callId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index 870f5ee..f5689d8 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -34,6 +34,7 @@
private PhoneAccountHandle mPhoneAccount;
private int mState;
private int mConnectionCapabilities;
+ private int mConnectionProperties;
private List<String> mConnectionIds;
private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
private final IVideoProvider mVideoProvider;
@@ -45,6 +46,7 @@
PhoneAccountHandle phoneAccount,
int state,
int connectionCapabilities,
+ int connectionProperties,
List<String> connectionIds,
IVideoProvider videoProvider,
int videoState,
@@ -54,6 +56,7 @@
mPhoneAccount = phoneAccount;
mState = state;
mConnectionCapabilities = connectionCapabilities;
+ mConnectionProperties = connectionProperties;
mConnectionIds = connectionIds;
mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
mVideoProvider = videoProvider;
@@ -72,6 +75,8 @@
.append(Connection.stateToString(mState))
.append(", capabilities: ")
.append(Connection.capabilitiesToString(mConnectionCapabilities))
+ .append(", properties: ")
+ .append(Connection.propertiesToString(mConnectionProperties))
.append(", connectTime: ")
.append(mConnectTimeMillis)
.append(", children: ")
@@ -95,6 +100,10 @@
return mConnectionCapabilities;
}
+ public int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
public List<String> getConnectionIds() {
return mConnectionIds;
}
@@ -134,9 +143,11 @@
int videoState = source.readInt();
StatusHints statusHints = source.readParcelable(classLoader);
Bundle extras = source.readBundle(classLoader);
+ int properties = source.readInt();
- return new ParcelableConference(phoneAccount, state, capabilities, connectionIds,
- videoCallProvider, videoState, connectTimeMillis, statusHints, extras);
+ return new ParcelableConference(phoneAccount, state, capabilities, properties,
+ connectionIds, videoCallProvider, videoState, connectTimeMillis, statusHints,
+ extras);
}
@Override
@@ -164,5 +175,6 @@
destination.writeInt(mVideoState);
destination.writeParcelable(mStatusHints, 0);
destination.writeBundle(mExtras);
+ destination.writeInt(mConnectionProperties);
}
}
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index ce51c96..540f388 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -36,6 +36,7 @@
private final PhoneAccountHandle mPhoneAccount;
private final int mState;
private final int mConnectionCapabilities;
+ private final int mConnectionProperties;
private final Uri mAddress;
private final int mAddressPresentation;
private final String mCallerDisplayName;
@@ -55,6 +56,7 @@
PhoneAccountHandle phoneAccount,
int state,
int capabilities,
+ int properties,
Uri address,
int addressPresentation,
String callerDisplayName,
@@ -71,6 +73,7 @@
mPhoneAccount = phoneAccount;
mState = state;
mConnectionCapabilities = capabilities;
+ mConnectionProperties = properties;
mAddress = address;
mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName;
@@ -94,11 +97,26 @@
return mState;
}
- // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
+ /**
+ * Returns the current connection capabilities bit-mask. Connection capabilities are defined as
+ * {@code CAPABILITY_*} constants in {@link Connection}.
+ *
+ * @return Bit-mask containing capabilities of the connection.
+ */
public int getConnectionCapabilities() {
return mConnectionCapabilities;
}
+ /**
+ * Returns the current connection properties bit-mask. Connection properties are defined as
+ * {@code PROPERTY_*} constants in {@link Connection}.
+ *
+ * @return Bit-mask containing properties of the connection.
+ */
+ public int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
public Uri getHandle() {
return mAddress;
}
@@ -160,6 +178,8 @@
.append(mState)
.append(", capabilities:")
.append(Connection.capabilitiesToString(mConnectionCapabilities))
+ .append(", properties:")
+ .append(Connection.propertiesToString(mConnectionProperties))
.append(", extras:")
.append(mExtras)
.toString();
@@ -189,11 +209,13 @@
List<String> conferenceableConnectionIds = new ArrayList<>();
source.readStringList(conferenceableConnectionIds);
Bundle extras = Bundle.setDefusable(source.readBundle(classLoader), true);
+ int properties = source.readInt();
return new ParcelableConnection(
phoneAccount,
state,
capabilities,
+ properties,
address,
addressPresentation,
callerDisplayName,
@@ -241,5 +263,6 @@
destination.writeParcelable(mDisconnectCause, 0);
destination.writeStringList(mConferenceableConnectionIds);
destination.writeBundle(mExtras);
+ destination.writeInt(mConnectionProperties);
}
}
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index b03cb51..943da6d 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -92,6 +92,18 @@
int connectionCapabilities) {}
/**
+ * Indicates that the call properties of this {@code RemoteConference} have changed.
+ * See {@link #getConnectionProperties()}.
+ *
+ * @param conference The {@code RemoteConference} invoking this method.
+ * @param connectionProperties The new properties of the {@code RemoteConference}.
+ */
+ public void onConnectionPropertiesChanged(
+ RemoteConference conference,
+ int connectionProperties) {}
+
+
+ /**
* Invoked when the set of {@link RemoteConnection}s which can be added to this conference
* call have changed.
*
@@ -133,6 +145,7 @@
private int mState = Connection.STATE_NEW;
private DisconnectCause mDisconnectCause;
private int mConnectionCapabilities;
+ private int mConnectionProperties;
private Bundle mExtras;
/** @hide */
@@ -244,6 +257,24 @@
}
/** @hide */
+ void setConnectionProperties(final int connectionProperties) {
+ if (mConnectionProperties != connectionProperties) {
+ mConnectionProperties = connectionProperties;
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final RemoteConference conference = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onConnectionPropertiesChanged(
+ conference, mConnectionProperties);
+ }
+ });
+ }
+ }
+ }
+
+ /** @hide */
void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
mConferenceableConnections.clear();
mConferenceableConnections.addAll(conferenceableConnections);
@@ -342,6 +373,16 @@
}
/**
+ * Returns the properties of the conference. See {@code PROPERTY_*} constants in class
+ * {@link Connection} for valid values.
+ *
+ * @return A bitmask of the properties of the conference call.
+ */
+ public final int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
+ /**
* Obtain the extras associated with this {@code RemoteConnection}.
*
* @return The extras for this connection.
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 7df6678..dc8eaf6 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -90,6 +90,17 @@
int connectionCapabilities) {}
/**
+ * Indicates that the call properties of this {@code RemoteConnection} have changed.
+ * See {@link #getConnectionProperties()}.
+ *
+ * @param connection The {@code RemoteConnection} invoking this method.
+ * @param connectionProperties The new properties of the {@code RemoteConnection}.
+ */
+ public void onConnectionPropertiesChanged(
+ RemoteConnection connection,
+ int connectionProperties) {}
+
+ /**
* Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a
* pause character. This causes the post-dial signals to stop pending user confirmation. An
* implementation should present this choice to the user and invoke
@@ -588,6 +599,7 @@
private boolean mRingbackRequested;
private boolean mConnected;
private int mConnectionCapabilities;
+ private int mConnectionProperties;
private int mVideoState;
private VideoProvider mVideoProvider;
private boolean mIsVoipAudioMode;
@@ -624,6 +636,7 @@
mDisconnectCause = connection.getDisconnectCause();
mRingbackRequested = connection.isRingbackRequested();
mConnectionCapabilities = connection.getConnectionCapabilities();
+ mConnectionProperties = connection.getConnectionProperties();
mVideoState = connection.getVideoState();
mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
mIsVoipAudioMode = connection.getIsVoipAudioMode();
@@ -719,6 +732,16 @@
}
/**
+ * Obtains the properties of this {@code RemoteConnection}.
+ *
+ * @return A bitmask of the properties of the {@code RemoteConnection}, as defined in the
+ * {@code PROPERTY_*} constants in class {@link Connection}.
+ */
+ public int getConnectionProperties() {
+ return mConnectionProperties;
+ }
+
+ /**
* Determines if the audio mode of this {@code RemoteConnection} is VOIP.
*
* @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP.
@@ -1114,6 +1137,23 @@
/**
* @hide
*/
+ void setConnectionProperties(final int connectionProperties) {
+ mConnectionProperties = connectionProperties;
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onConnectionPropertiesChanged(connection, connectionProperties);
+ }
+ });
+ }
+ }
+
+ /**
+ * @hide
+ */
void setDestroyed() {
if (!mCallbackRecords.isEmpty()) {
// Make sure that the callbacks are notified that the call is destroyed first.
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index d88d007..21a7706 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -61,6 +61,7 @@
mPendingConnections.remove(connection);
// Unconditionally initialize the connection ...
connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
+ connection.setConnectionProperties(parcel.getConnectionProperties());
if (parcel.getHandle() != null
|| parcel.getState() != Connection.STATE_DISCONNECTED) {
connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
@@ -156,6 +157,17 @@
}
@Override
+ public void setConnectionProperties(String callId, int connectionProperties) {
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "setConnectionProperties")
+ .setConnectionProperties(connectionProperties);
+ } else {
+ findConferenceForAction(callId, "setConnectionProperties")
+ .setConnectionProperties(connectionProperties);
+ }
+ }
+
+ @Override
public void setIsConferenced(String callId, String conferenceCallId) {
// Note: callId should not be null; conferenceCallId may be null
RemoteConnection connection =
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 6804805..9bc8ffe 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -55,6 +55,8 @@
void setConnectionCapabilities(String callId, int connectionCapabilities);
+ void setConnectionProperties(String callId, int connectionProperties);
+
void setIsConferenced(String callId, String conferenceCallId);
void setConferenceMergeFailed(String callId);
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 96c6243..303746c 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -201,7 +201,7 @@
* "14" vs (int) 14).
* Note: This is used by {@link com.android.internal.telephony.imsphone.ImsPhoneConnection#
* updateWifiStateFromExtras(Bundle)} to determine whether to set the
- * {@link android.telecom.Connection#CAPABILITY_WIFI} capability on a connection.
+ * {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
*/
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7904759..06dea07 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1556,18 +1556,6 @@
return sbuf.toString();
}
- /**
- * Construct a WifiConfiguration from a scanned network
- * @param scannedAP the scan result used to construct the config entry
- * TODO: figure out whether this is a useful way to construct a new entry.
- *
- public WifiConfiguration(ScanResult scannedAP) {
- networkId = -1;
- SSID = scannedAP.SSID;
- BSSID = scannedAP.BSSID;
- }
- */
-
/** {@hide} */
public String getPrintableSsid() {
if (SSID == null) return "";
@@ -1881,11 +1869,6 @@
}
}
- /** {@hide} */
- //public static final int NOTHING_TAG = 0;
- /** {@hide} */
- //public static final int SCAN_CACHE_TAG = 1;
-
/** Implement the Parcelable interface {@hide} */
@Override
public void writeToParcel(Parcel dest, int flags) {