Merge "Track libcore change df3cf7e4cf590086d1cdd09b6e0d3104de167e61." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index d507aee..99a6430 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";
}
@@ -23053,6 +23053,7 @@
method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
method public abstract void onTune(android.net.Uri);
+ method public void onTune(android.net.Uri, android.os.Bundle);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23102,6 +23103,7 @@
method public void startRecording(android.net.Uri);
method public void stopRecording();
method public void tune(java.lang.String, android.net.Uri);
+ method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
}
public static abstract class TvRecordingClient.RecordingCallback {
@@ -30396,6 +30398,7 @@
public class BlockedNumberContract {
method public static boolean canCurrentUserBlockNumbers(android.content.Context);
method public static boolean isBlocked(android.content.Context, java.lang.String);
+ method public static int unblock(android.content.Context, java.lang.String);
field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
field public static final android.net.Uri AUTHORITY_URI;
}
@@ -32388,6 +32391,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
@@ -34577,7 +34581,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -36141,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();
@@ -36168,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);
@@ -36197,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();
@@ -36222,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);
@@ -36230,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);
@@ -36246,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
@@ -36269,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
@@ -36491,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();
@@ -36513,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);
@@ -36531,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();
@@ -36560,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);
@@ -43664,7 +43677,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3fdfeb8..d27923b 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";
}
@@ -32711,6 +32711,7 @@
public class BlockedNumberContract {
method public static boolean canCurrentUserBlockNumbers(android.content.Context);
method public static boolean isBlocked(android.content.Context, java.lang.String);
+ method public static int unblock(android.content.Context, java.lang.String);
field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
field public static final android.net.Uri AUTHORITY_URI;
}
@@ -34835,6 +34836,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
@@ -37027,7 +37029,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -38712,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();
@@ -38742,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);
@@ -38772,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();
@@ -38798,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);
@@ -38806,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);
@@ -38822,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
@@ -38845,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
@@ -39122,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();
@@ -39145,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);
@@ -39163,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();
@@ -39193,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);
@@ -46391,7 +46402,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/test-current.txt b/api/test-current.txt
index cc66d6b..7f16995 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";
}
@@ -23118,6 +23118,7 @@
method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
method public abstract void onTune(android.net.Uri);
+ method public void onTune(android.net.Uri, android.os.Bundle);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23167,6 +23168,7 @@
method public void startRecording(android.net.Uri);
method public void stopRecording();
method public void tune(java.lang.String, android.net.Uri);
+ method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
}
public static abstract class TvRecordingClient.RecordingCallback {
@@ -30465,6 +30467,7 @@
public class BlockedNumberContract {
method public static boolean canCurrentUserBlockNumbers(android.content.Context);
method public static boolean isBlocked(android.content.Context, java.lang.String);
+ method public static int unblock(android.content.Context, java.lang.String);
field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
field public static final android.net.Uri AUTHORITY_URI;
}
@@ -32457,6 +32460,7 @@
field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+ field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
@@ -34648,7 +34652,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -36212,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();
@@ -36239,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);
@@ -36268,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();
@@ -36293,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);
@@ -36301,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);
@@ -36317,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
@@ -36340,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
@@ -36562,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();
@@ -36584,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);
@@ -36602,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();
@@ -36631,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);
@@ -43737,7 +43750,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index ea53e59..c597ed2 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -68,14 +68,11 @@
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation() : Thread(false), mZip(NULL), mClockEnabled(true) {
+BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
mSession = new SurfaceComposerClient();
}
BootAnimation::~BootAnimation() {
- if (mZip != NULL) {
- delete mZip;
- }
}
void BootAnimation::onFirstRef() {
@@ -288,19 +285,15 @@
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
- ZipFileRO* zipFile = NULL;
- if ((encryptedAnimation &&
- (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
- ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
-
- ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) ||
-
- ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
- mZip = zipFile;
+ if (encryptedAnimation && (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
+ mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
}
-
+ else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) {
+ mZipFileName = OEM_BOOTANIMATION_FILE;
+ }
+ else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) {
+ mZipFileName = SYSTEM_BOOTANIMATION_FILE;
+ }
return NO_ERROR;
}
@@ -309,7 +302,7 @@
bool r;
// We have no bootanimation file, so we use the stock android logo
// animation.
- if (mZip == NULL) {
+ if (mZipFileName.isEmpty()) {
r = android();
} else {
r = movie();
@@ -429,16 +422,17 @@
return true;
}
-bool BootAnimation::readFile(const char* name, String8& outString)
+
+static bool readFile(ZipFileRO* zip, const char* name, String8& outString)
{
- ZipEntryRO entry = mZip->findEntryByName(name);
+ ZipEntryRO entry = zip->findEntryByName(name);
ALOGE_IF(!entry, "couldn't find %s", name);
if (!entry) {
return false;
}
- FileMap* entryMap = mZip->createEntryFileMap(entry);
- mZip->releaseEntry(entry);
+ FileMap* entryMap = zip->createEntryFileMap(entry);
+ zip->releaseEntry(entry);
ALOGE_IF(!entryMap, "entryMap is null");
if (!entryMap) {
return false;
@@ -512,18 +506,18 @@
glBindTexture(GL_TEXTURE_2D, 0);
}
-bool BootAnimation::movie()
+bool BootAnimation::parseAnimationDesc(Animation& animation)
{
String8 desString;
- if (!readFile("desc.txt", desString)) {
+ if (!readFile(animation.zip, "desc.txt", desString)) {
return false;
}
char const* s = desString.string();
// Create and initialize an AudioPlayer if we have an audio_conf.txt file
String8 audioConf;
- if (readFile("audio_conf.txt", audioConf)) {
+ if (readFile(animation.zip, "audio_conf.txt", audioConf)) {
mAudioPlayer = new AudioPlayer;
if (!mAudioPlayer->init(audioConf.string())) {
ALOGE("mAudioPlayer.init failed");
@@ -531,8 +525,6 @@
}
}
- Animation animation;
-
// Parse the description file
for (;;) {
const char* endl = strstr(s, "\n");
@@ -564,6 +556,7 @@
part.path = path;
part.clockPosY = clockPosY;
part.audioFile = NULL;
+ part.animation = NULL;
if (!parseColor(color, part.backgroundColor)) {
ALOGE("> invalid color '#%s'", color);
part.backgroundColor[0] = 0.0f;
@@ -572,13 +565,29 @@
}
animation.parts.add(part);
}
-
+ else if (strcmp(l, "$SYSTEM") == 0) {
+ // ALOGD("> SYSTEM");
+ Animation::Part part;
+ part.playUntilComplete = false;
+ part.count = 1;
+ part.pause = 0;
+ part.audioFile = NULL;
+ part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
+ if (part.animation != NULL)
+ animation.parts.add(part);
+ }
s = ++endl;
}
+ return true;
+}
+
+bool BootAnimation::preloadZip(Animation& animation)
+{
// read all the data structures
const size_t pcount = animation.parts.size();
void *cookie = NULL;
+ ZipFileRO* mZip = animation.zip;
if (!mZip->startIteration(&cookie)) {
return false;
}
@@ -624,6 +633,16 @@
mZip->endIteration(cookie);
+ return true;
+}
+
+bool BootAnimation::movie()
+{
+
+ Animation* animation = loadAnimation(mZipFileName);
+ if (animation == NULL)
+ return false;
+
// Blend required to draw time on top of animation frames.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
@@ -645,6 +664,19 @@
mClockEnabled = clockTextureInitialized;
}
+ playAnimation(*animation);
+ releaseAnimation(animation);
+
+ if (clockTextureInitialized) {
+ glDeleteTextures(1, &mClock.name);
+ }
+
+ return false;
+}
+
+bool BootAnimation::playAnimation(const Animation& animation)
+{
+ const size_t pcount = animation.parts.size();
const int xc = (mWidth - animation.width) / 2;
const int yc = ((mHeight - animation.height) / 2);
nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -657,6 +689,14 @@
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
+ // Handle animation package
+ if (part.animation != NULL) {
+ playAnimation(*part.animation);
+ if (exitPending())
+ break;
+ continue; //to next part
+ }
+
for (int r=0 ; !part.count || r<part.count ; r++) {
// Exit any non playuntil complete parts immediately
if(exitPending() && !part.playUntilComplete)
@@ -744,14 +784,46 @@
}
}
}
-
- if (clockTextureInitialized) {
- glDeleteTextures(1, &mClock.name);
- }
-
- return false;
+ return true;
}
+void BootAnimation::releaseAnimation(Animation* animation) const
+{
+ for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
+ e = animation->parts.end(); it != e; ++it) {
+ if (it->animation)
+ releaseAnimation(it->animation);
+ }
+ if (animation->zip)
+ delete animation->zip;
+ delete animation;
+}
+
+BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
+{
+ if (mLoadedFiles.indexOf(fn) >= 0) {
+ ALOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
+ fn.string());
+ return NULL;
+ }
+ ZipFileRO *zip = ZipFileRO::open(fn);
+ if (zip == NULL) {
+ ALOGE("Failed to open animation zip \"%s\": %s",
+ fn.string(), strerror(errno));
+ return NULL;
+ }
+
+ Animation *animation = new Animation;
+ animation->fileName = fn;
+ animation->zip = zip;
+ mLoadedFiles.add(animation->fileName);
+
+ parseAnimationDesc(*animation);
+ preloadZip(*animation);
+
+ mLoadedFiles.remove(fn);
+ return animation;
+}
// ---------------------------------------------------------------------------
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 83e2b38..d49e1ec 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -76,19 +76,27 @@
bool playUntilComplete;
float backgroundColor[3];
FileMap* audioFile;
+ Animation* animation;
};
int fps;
int width;
int height;
Vector<Part> parts;
+ String8 audioConf;
+ String8 fileName;
+ ZipFileRO* zip;
};
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(const Animation::Frame& frame);
bool android();
- bool readFile(const char* name, String8& outString);
bool movie();
void drawTime(const Texture& clockTex, const int yPos);
+ Animation* loadAnimation(const String8&);
+ bool playAnimation(const Animation&);
+ void releaseAnimation(Animation*) const;
+ bool parseAnimationDesc(Animation&);
+ bool preloadZip(Animation &animation);
void checkExit();
@@ -104,8 +112,9 @@
EGLDisplay mSurface;
sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
- ZipFileRO *mZip;
bool mClockEnabled;
+ String8 mZipFileName;
+ SortedVector<String8> mLoadedFiles;
};
// ---------------------------------------------------------------------------
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cc1d68e..ee17e8a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -57,6 +57,7 @@
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
+import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -91,6 +92,8 @@
import android.view.ContextThemeWrapper;
import android.view.DragEvent;
import android.view.DropPermissions;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -1679,10 +1682,16 @@
}
@Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
if (menu == null) {
return;
}
+ final InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
+ if (inputDevice == null) {
+ return;
+ }
+ final KeyCharacterMap keyCharacterMap = inputDevice.getKeyCharacterMap();
KeyboardShortcutGroup group = null;
int menuSize = menu.size();
for (int i = 0; i < menuSize; ++i) {
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/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5b7dae6..ed590e6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -272,12 +272,17 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
throws NameNotFoundException {
try {
- List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags).getList();
- if (pi != null) {
- return pi;
+ ParceledListSlice<PermissionInfo> parceledList =
+ mPM.queryPermissionsByGroup(group, flags);
+ if (parceledList != null) {
+ List<PermissionInfo> pi = parceledList.getList();
+ if (pi != null) {
+ return pi;
+ }
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -288,7 +293,7 @@
@Override
public PermissionGroupInfo getPermissionGroupInfo(String name,
- int flags) throws NameNotFoundException {
+ int flags) throws NameNotFoundException {
try {
PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
if (pgi != null) {
@@ -302,9 +307,15 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
try {
- return mPM.getAllPermissionGroups(flags).getList();
+ ParceledListSlice<PermissionGroupInfo> parceledList =
+ mPM.getAllPermissionGroups(flags);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -439,9 +450,15 @@
}
@Override
+ @SuppressWarnings("unchecked")
public FeatureInfo[] getSystemAvailableFeatures() {
try {
- final List<FeatureInfo> list = mPM.getSystemAvailableFeatures().getList();
+ ParceledListSlice<FeatureInfo> parceledList =
+ mPM.getSystemAvailableFeatures();
+ if (parceledList == null) {
+ return new FeatureInfo[0];
+ }
+ final List<FeatureInfo> list = parceledList.getList();
final FeatureInfo[] res = new FeatureInfo[list.size()];
for (int i = 0; i < res.length; i++) {
res[i] = list.get(i);
@@ -636,10 +653,15 @@
/** @hide */
@Override
+ @SuppressWarnings("unchecked")
public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
try {
- ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
- return slice.getList();
+ ParceledListSlice<PackageInfo> parceledList =
+ mPM.getInstalledPackages(flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -651,9 +673,12 @@
String[] permissions, int flags) {
final int userId = mContext.getUserId();
try {
- ParceledListSlice<PackageInfo> slice = mPM.getPackagesHoldingPermissions(
- permissions, flags, userId);
- return slice.getList();
+ ParceledListSlice<PackageInfo> parceledList =
+ mPM.getPackagesHoldingPermissions(permissions, flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -664,8 +689,12 @@
public List<ApplicationInfo> getInstalledApplications(int flags) {
final int userId = mContext.getUserId();
try {
- ParceledListSlice<ApplicationInfo> slice = mPM.getInstalledApplications(flags, userId);
- return slice.getList();
+ ParceledListSlice<ApplicationInfo> parceledList =
+ mPM.getInstalledApplications(flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -770,20 +799,25 @@
/** @hide Same as above but for a specific user */
@Override
+ @SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
- int flags, int userId) {
+ int flags, int userId) {
try {
- return mPM.queryIntentActivities(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
- userId).getList();
+ ParceledListSlice<ResolveInfo> parceledList =
+ mPM.queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
+ @SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentActivityOptions(
ComponentName caller, Intent[] specifics, Intent intent,
int flags) {
@@ -807,10 +841,13 @@
}
try {
- return mPM
- .queryIntentActivityOptions(caller, specifics, specificTypes, intent,
- intent.resolveTypeIfNeeded(resolver), flags, mContext.getUserId())
- .getList();
+ ParceledListSlice<ResolveInfo> parceledList =
+ mPM.queryIntentActivityOptions(caller, specifics, specificTypes, intent,
+ intent.resolveTypeIfNeeded(resolver), flags, mContext.getUserId());
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -820,13 +857,17 @@
* @hide
*/
@Override
+ @SuppressWarnings("unchecked")
public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
try {
- return mPM.queryIntentReceivers(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
- userId).getList();
+ ParceledListSlice<ResolveInfo> parceledList =
+ mPM.queryIntentReceivers(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -851,13 +892,17 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
try {
- return mPM.queryIntentServices(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
- userId).getList();
+ ParceledListSlice<ResolveInfo> parceledList =
+ mPM.queryIntentServices(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -869,12 +914,18 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<ResolveInfo> queryIntentContentProvidersAsUser(
Intent intent, int flags, int userId) {
try {
- return mPM.queryIntentContentProviders(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId)
- .getList();
+ ParceledListSlice<ResolveInfo> parceledList =
+ mPM.queryIntentContentProviders(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ flags, userId);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -901,12 +952,13 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<ProviderInfo> queryContentProviders(String processName,
- int uid, int flags) {
+ int uid, int flags) {
try {
- ParceledListSlice<ProviderInfo> slice
- = mPM.queryContentProviders(processName, uid, flags);
- return slice != null ? slice.getList() : null;
+ ParceledListSlice<ProviderInfo> slice =
+ mPM.queryContentProviders(processName, uid, flags);
+ return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -930,10 +982,16 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<InstrumentationInfo> queryInstrumentation(
String targetPackage, int flags) {
try {
- return mPM.queryInstrumentation(targetPackage, flags).getList();
+ ParceledListSlice<InstrumentationInfo> parceledList =
+ mPM.queryInstrumentation(targetPackage, flags);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1575,18 +1633,30 @@
}
@Override
+ @SuppressWarnings("unchecked")
public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
try {
- return mPM.getIntentFilterVerifications(packageName).getList();
+ ParceledListSlice<IntentFilterVerificationInfo> parceledList =
+ mPM.getIntentFilterVerifications(packageName);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
+ @SuppressWarnings("unchecked")
public List<IntentFilter> getAllIntentFilters(String packageName) {
try {
- return mPM.getAllIntentFilters(packageName).getList();
+ ParceledListSlice<IntentFilter> parceledList =
+ mPM.getAllIntentFilters(packageName);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 79461b4..0bb1097 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -1082,13 +1082,6 @@
}
/**
- * {@inheritDoc}
- */
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- }
-
- /**
* @return The activity associated with this dialog, or null if there is no associated activity.
*/
private ComponentName getAssociatedActivity() {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index ddd0ae9..d89c0e0 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -537,12 +537,10 @@
setTransitioningViewsVisiblity(View.INVISIBLE, false);
}
TransitionManager.beginDelayedTransition(decorView, transition);
- if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
- mSharedElements.get(0).invalidate();
- }
if (startEnterTransition) {
- setTransitioningViewsVisiblity(View.VISIBLE, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, false);
}
+ decorView.invalidate();
} else {
transitionStarted();
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index d54ffa0..ce017f6 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -268,7 +268,8 @@
if (transition != null && decorView != null && mTransitioningViews != null) {
setTransitioningViewsVisiblity(View.VISIBLE, false);
TransitionManager.beginDelayedTransition(decorView, transition);
- setTransitioningViewsVisiblity(View.INVISIBLE, true);
+ setTransitioningViewsVisiblity(View.INVISIBLE, false);
+ decorView.invalidate();
} else {
transitionStarted();
}
@@ -367,7 +368,7 @@
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
if (viewsTransition != null) {
- setTransitioningViewsVisiblity(View.INVISIBLE, true);
+ setTransitioningViewsVisiblity(View.INVISIBLE, false);
}
decorView.invalidate();
} else {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index db7ca2a..84605bb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1158,10 +1158,15 @@
StrictJarFile jarFile = null;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
+ // Ignore signature stripping protections when verifying APKs from system partition.
+ // For those APKs we only care about extracting signer certificates, and don't care
+ // about verifying integrity.
+ boolean signatureSchemeRollbackProtectionsEnforced =
+ (parseFlags & PARSE_IS_SYSTEM) == 0;
jarFile = new StrictJarFile(
apkPath,
- !verified // whether to verify JAR signature
- );
+ !verified, // whether to verify JAR signature
+ signatureSchemeRollbackProtectionsEnforced);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Always verify manifest, regardless of source
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d847cd0..b32b2cc 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,6 +18,7 @@
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -68,6 +69,7 @@
public static final int MATCH_MOBILE_WILDCARD = 6;
public static final int MATCH_WIFI_WILDCARD = 7;
public static final int MATCH_BLUETOOTH = 8;
+ public static final int MATCH_PROXY = 9;
/**
* Set of {@link NetworkInfo#getType()} that reflect data usage.
@@ -157,6 +159,14 @@
return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
}
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
+ * networks together.
+ */
+ public static NetworkTemplate buildTemplateProxy() {
+ return new NetworkTemplate(MATCH_PROXY, null, null);
+ }
+
private final int mMatchRule;
private final String mSubscriberId;
@@ -293,6 +303,8 @@
return matchesWifiWildcard(ident);
case MATCH_BLUETOOTH:
return matchesBluetooth(ident);
+ case MATCH_PROXY:
+ return matchesProxy(ident);
default:
throw new IllegalArgumentException("unknown network template");
}
@@ -401,6 +413,13 @@
return false;
}
+ /**
+ * Check if matches Proxy network template.
+ */
+ private boolean matchesProxy(NetworkIdentity ident) {
+ return ident.mType == TYPE_PROXY;
+ }
+
private static String getMatchRuleName(int matchRule) {
switch (matchRule) {
case MATCH_MOBILE_3G_LOWER:
@@ -419,6 +438,8 @@
return "WIFI_WILDCARD";
case MATCH_BLUETOOTH:
return "BLUETOOTH";
+ case MATCH_PROXY:
+ return "PROXY";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e730ad8..be82d56a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,8 @@
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.ArrayMap;
+import android.util.MutableBoolean;
+import android.util.Pair;
import android.util.Printer;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -5317,26 +5319,28 @@
}
if (apps != null) {
- SparseArray<ArrayList<String>> uids = new SparseArray<ArrayList<String>>();
+ SparseArray<Pair<ArrayList<String>, MutableBoolean>> uids = new SparseArray<>();
for (int i=0; i<apps.size(); i++) {
ApplicationInfo ai = apps.get(i);
- ArrayList<String> pkgs = uids.get(ai.uid);
+ Pair<ArrayList<String>, MutableBoolean> pkgs = uids.get(
+ UserHandle.getAppId(ai.uid));
if (pkgs == null) {
- pkgs = new ArrayList<String>();
- uids.put(ai.uid, pkgs);
+ pkgs = new Pair<>(new ArrayList<String>(), new MutableBoolean(false));
+ uids.put(UserHandle.getAppId(ai.uid), pkgs);
}
- pkgs.add(ai.packageName);
+ pkgs.first.add(ai.packageName);
}
SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
String[] lineArgs = new String[2];
for (int i=0; i<NU; i++) {
- int uid = uidStats.keyAt(i);
- ArrayList<String> pkgs = uids.get(uid);
- if (pkgs != null) {
- for (int j=0; j<pkgs.size(); j++) {
+ int uid = UserHandle.getAppId(uidStats.keyAt(i));
+ Pair<ArrayList<String>, MutableBoolean> pkgs = uids.get(uid);
+ if (pkgs != null && !pkgs.second.value) {
+ pkgs.second.value = true;
+ for (int j=0; j<pkgs.first.size(); j++) {
lineArgs[0] = Integer.toString(uid);
- lineArgs[1] = pkgs.get(j);
+ lineArgs[1] = pkgs.first.get(j);
dumpLine(pw, 0 /* uid */, "i" /* category */, UID_DATA,
(Object[])lineArgs);
}
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index 0f2e33d..f13e5b5 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -101,7 +101,8 @@
* {@link #UNDEFINED_TEMPERATURE} if undefined.
* Empty if platform doesn't provide the queried temperature.
*
- * @throws SecurityException if a non profile or device owner tries to call this method.
+ * @throws SecurityException if something other than the profile or device owner, or the
+ * current VR service tries to retrieve information provided by this service.
*/
public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type,
@TemperatureSource int source) {
@@ -137,7 +138,8 @@
* each unplugged core.
* Empty if CPU usage is not supported on this system.
*
- * @throws SecurityException if a non profile or device owner tries to call this method.
+ * @throws SecurityException if something other than the profile or device owner, or the
+ * current VR service tries to retrieve information provided by this service.
*/
public @NonNull CpuUsageInfo[] getCpuUsages() {
try {
@@ -153,7 +155,8 @@
* @return an array of float fan speeds in RPM. Empty if there are no fans or fan speed is not
* supported on this system.
*
- * @throws SecurityException if a non profile or device owner tries to call this method.
+ * @throws SecurityException if something other than the profile or device owner, or the
+ * current VR service tries to retrieve information provided by this service.
*/
public @NonNull float[] getFanSpeeds() {
try {
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 17176ec..34c0b14 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,7 +16,6 @@
package android.os.storage;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
@@ -336,7 +335,7 @@
*
* @see DocumentsContract
*/
- public Intent createAccessIntent(@NonNull String directoryName) {
+ public Intent createAccessIntent(String directoryName) {
final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
intent.putExtra(EXTRA_STORAGE_VOLUME, this);
intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 6fe0189..e90dc9c 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -15,6 +15,7 @@
*/
package android.provider;
+import android.annotation.WorkerThread;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
@@ -109,6 +110,8 @@
* Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
* getContentResolver().delete(uri, null, null);
* </pre>
+ * To check if a particular number is blocked, use the method
+ * {@link #isBlocked(Context, String)}.
* </p>
* </dd>
* <dt><b>Query</b></dt>
@@ -120,8 +123,12 @@
* new String[]{BlockedNumbers.COLUMN_ID, BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
* BlockedNumbers.COLUMN_E164_NUMBER}, null, null, null);
* </pre>
- * To check if a particular number is blocked, use the method
- * {@link #isBlocked(Context, String)}.
+ * </p>
+ * </dd>
+ * <dt><b>Unblock</b></dt>
+ * <dd>
+ * <p>
+ * Use the method {@link #unblock(Context, String)} to unblock numbers.
* </p>
* </dd>
*
@@ -206,9 +213,15 @@
public static final String METHOD_IS_BLOCKED = "is_blocked";
/** @hide */
+ public static final String METHOD_UNBLOCK= "unblock";
+
+ /** @hide */
public static final String RES_NUMBER_IS_BLOCKED = "blocked";
/** @hide */
+ public static final String RES_NUM_ROWS_DELETED = "num_deleted";
+
+ /** @hide */
public static final String METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS =
"can_current_user_block_numbers";
@@ -217,9 +230,15 @@
/**
* Returns whether a given number is in the blocked list.
+ *
+ * <p> This matches the {@code phoneNumber} against the
+ * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column, and the E164 representation of the
+ * {@code phoneNumber} with the {@link BlockedNumbers#COLUMN_E164_NUMBER} column.
+ *
* <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user
* context {@code context}, this method will throw an {@link UnsupportedOperationException}.
*/
+ @WorkerThread
public static boolean isBlocked(Context context, String phoneNumber) {
final Bundle res = context.getContentResolver().call(
AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null);
@@ -227,6 +246,30 @@
}
/**
+ * Unblocks the {@code phoneNumber} if it is blocked.
+ *
+ * <p> Returns the number of rows deleted in the blocked number provider as a result of unblock.
+ *
+ * <p> This deletes all rows where the {@code phoneNumber} matches the
+ * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column or the E164 representation of the
+ * {@code phoneNumber} matches the {@link BlockedNumbers#COLUMN_E164_NUMBER} column.
+ *
+ * <p>To delete rows based on exact match with specific columns such as
+ * {@link BlockedNumbers#COLUMN_ID} use
+ * {@link android.content.ContentProvider#delete(Uri, String, String[])} with
+ * {@link BlockedNumbers#CONTENT_URI} URI.
+ *
+ * <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user
+ * context {@code context}, this method will throw an {@link UnsupportedOperationException}.
+ */
+ @WorkerThread
+ public static int unblock(Context context, String phoneNumber) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_UNBLOCK, phoneNumber, null);
+ return res.getInt(RES_NUM_ROWS_DELETED, 0);
+ }
+
+ /**
* Returns {@code true} if blocking numbers is supported for the current user.
* <p> Typically, blocking numbers is only supported for one user at a time.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d8937b4..f7e0e03 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -322,6 +322,20 @@
"android.settings.PRIVACY_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of VPN.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_VPN_SETTINGS =
+ "android.settings.VPN_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of Wi-Fi.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -7699,6 +7713,16 @@
public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
/**
+ * Device Idle (Doze) specific settings for watches. See {@code #DEVICE_IDLE_CONSTANTS}
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.DeviceIdleController.Constants
+ */
+ public static final String DEVICE_IDLE_CONSTANTS_WATCH = "device_idle_constants_watch";
+
+ /**
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 816ecde..7af0b05 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -367,11 +367,6 @@
@Override
public void onActionModeFinished(ActionMode mode) {
}
-
- /** {@inheritDoc} */
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- }
// end Window.Callback methods
// begin public api
diff --git a/core/java/android/util/jar/StrictJarFile.java b/core/java/android/util/jar/StrictJarFile.java
index 302a08d..5d94b06 100644
--- a/core/java/android/util/jar/StrictJarFile.java
+++ b/core/java/android/util/jar/StrictJarFile.java
@@ -58,11 +58,22 @@
public StrictJarFile(String fileName)
throws IOException, SecurityException {
- this(fileName, true);
+ this(fileName, true, true);
}
- public StrictJarFile(String fileName, boolean verify)
- throws IOException, SecurityException {
+ /**
+ *
+ * @param verify whether to verify the file's JAR signatures and collect the corresponding
+ * signer certificates.
+ * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against
+ * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or
+ * {@code false} to ignore any such protections. This parameter is ignored when
+ * {@code verify} is {@code false}.
+ */
+ public StrictJarFile(String fileName,
+ boolean verify,
+ boolean signatureSchemeRollbackProtectionsEnforced)
+ throws IOException, SecurityException {
this.nativeHandle = nativeOpenJarFile(fileName);
this.raf = new RandomAccessFile(fileName, "r");
@@ -73,7 +84,12 @@
if (verify) {
HashMap<String, byte[]> metaEntries = getMetaEntries();
this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
- this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries);
+ this.verifier =
+ new StrictJarVerifier(
+ fileName,
+ manifest,
+ metaEntries,
+ signatureSchemeRollbackProtectionsEnforced);
Set<String> files = manifest.getEntries().keySet();
for (String file : files) {
if (findEntry(file) == null) {
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index 0546a5f..6da50ba 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -72,6 +72,7 @@
private final StrictJarManifest manifest;
private final HashMap<String, byte[]> metaEntries;
private final int mainAttributesEnd;
+ private final boolean signatureSchemeRollbackProtectionsEnforced;
private final Hashtable<String, HashMap<String, Attributes>> signatures =
new Hashtable<String, HashMap<String, Attributes>>(5);
@@ -164,13 +165,19 @@
*
* @param name
* the name of the JAR file being verified.
+ *
+ * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against
+ * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or
+ * {@code false} to ignore any such protections.
*/
StrictJarVerifier(String name, StrictJarManifest manifest,
- HashMap<String, byte[]> metaEntries) {
+ HashMap<String, byte[]> metaEntries, boolean signatureSchemeRollbackProtectionsEnforced) {
jarName = name;
this.manifest = manifest;
this.metaEntries = metaEntries;
this.mainAttributesEnd = manifest.getMainAttributesEnd();
+ this.signatureSchemeRollbackProtectionsEnforced =
+ signatureSchemeRollbackProtectionsEnforced;
}
/**
@@ -357,40 +364,42 @@
return;
}
- // Check whether APK Signature Scheme v2 signature was stripped.
- String apkSignatureSchemeIdList =
- attributes.getValue(
- ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
- if (apkSignatureSchemeIdList != null) {
- // This field contains a comma-separated list of APK signature scheme IDs which were
- // used to sign this APK. If an ID is known to us, it means signatures of that scheme
- // were stripped from the APK because otherwise we wouldn't have fallen back to
- // verifying the APK using the JAR signature scheme.
- boolean v2SignatureGenerated = false;
- StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
- while (tokenizer.hasMoreTokens()) {
- String idText = tokenizer.nextToken().trim();
- if (idText.isEmpty()) {
- continue;
+ // If requested, check whether APK Signature Scheme v2 signature was stripped.
+ if (signatureSchemeRollbackProtectionsEnforced) {
+ String apkSignatureSchemeIdList =
+ attributes.getValue(
+ ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME);
+ if (apkSignatureSchemeIdList != null) {
+ // This field contains a comma-separated list of APK signature scheme IDs which
+ // were used to sign this APK. If an ID is known to us, it means signatures of that
+ // scheme were stripped from the APK because otherwise we wouldn't have fallen back
+ // to verifying the APK using the JAR signature scheme.
+ boolean v2SignatureGenerated = false;
+ StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
+ while (tokenizer.hasMoreTokens()) {
+ String idText = tokenizer.nextToken().trim();
+ if (idText.isEmpty()) {
+ continue;
+ }
+ int id;
+ try {
+ id = Integer.parseInt(idText);
+ } catch (Exception ignored) {
+ continue;
+ }
+ if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
+ // This APK was supposed to be signed with APK Signature Scheme v2 but no
+ // such signature was found.
+ v2SignatureGenerated = true;
+ break;
+ }
}
- int id;
- try {
- id = Integer.parseInt(idText);
- } catch (Exception ignored) {
- continue;
- }
- if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) {
- // This APK was supposed to be signed with APK Signature Scheme v2 but no such
- // signature was found.
- v2SignatureGenerated = true;
- break;
- }
- }
- if (v2SignatureGenerated) {
- throw new SecurityException(signatureFile + " indicates " + jarName + " is signed"
- + " using APK Signature Scheme v2, but no such signature was found."
- + " Signature stripped?");
+ if (v2SignatureGenerated) {
+ throw new SecurityException(signatureFile + " indicates " + jarName
+ + " is signed using APK Signature Scheme v2, but no such signature was"
+ + " found. Signature stripped?");
+ }
}
}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a12434c..41c44f1 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -51,8 +52,8 @@
* @param paint The paint used when the layer is drawn into the destination canvas.
* @see View#setLayerPaint(android.graphics.Paint)
*/
- public void setLayerPaint(Paint paint) {
- nSetLayerPaint(mFinalizer.get(), paint.getNativeInstance());
+ public void setLayerPaint(@Nullable Paint paint) {
+ nSetLayerPaint(mFinalizer.get(), paint != null ? paint.getNativeInstance() : 0);
mRenderer.pushLayerUpdate(this);
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 70d0513..707300f 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -95,5 +95,5 @@
/**
* Called when Keyboard Shortcuts are requested for the window.
*/
- void requestAppKeyboardShortcuts(IResultReceiver receiver);
+ void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index d8b7421..7af4a1f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -387,7 +387,7 @@
*
* @param receiver The receiver to deliver the results to.
*/
- void requestAppKeyboardShortcuts(IResultReceiver receiver);
+ void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
/**
* Retrieves the current stable insets from the primary display.
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a45c18d..a19254f 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -259,7 +259,7 @@
return nSetLayerType(mNativeRenderNode, layerType);
}
- public boolean setLayerPaint(Paint paint) {
+ public boolean setLayerPaint(@Nullable Paint paint) {
return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 1be4810..1a712c3 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -133,7 +134,6 @@
*/
public TextureView(Context context) {
super(context);
- init();
}
/**
@@ -144,7 +144,6 @@
*/
public TextureView(Context context, AttributeSet attrs) {
super(context, attrs);
- init();
}
/**
@@ -158,7 +157,6 @@
*/
public TextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- init();
}
/**
@@ -176,11 +174,6 @@
*/
public TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- mLayerPaint = new Paint();
}
/**
@@ -260,7 +253,7 @@
* method will however be taken into account when rendering the content of
* this TextureView.
*
- * @param layerType The ype of layer to use with this view, must be one of
+ * @param layerType The type of layer to use with this view, must be one of
* {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
* {@link #LAYER_TYPE_HARDWARE}
* @param paint The paint used to compose the layer. This argument is optional
@@ -268,16 +261,16 @@
* {@link #LAYER_TYPE_NONE}
*/
@Override
- public void setLayerType(int layerType, Paint paint) {
- if (paint != mLayerPaint) {
- mLayerPaint = paint == null ? new Paint() : paint;
- invalidate();
- }
+ public void setLayerType(int layerType, @Nullable Paint paint) {
+ setLayerPaint(paint);
}
@Override
- public void setLayerPaint(Paint paint) {
- setLayerType(/* ignored */ 0, paint);
+ public void setLayerPaint(@Nullable Paint paint) {
+ if (paint != mLayerPaint) {
+ mLayerPaint = paint;
+ invalidate();
+ }
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6d35a58..83c6e9e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11741,7 +11741,7 @@
}
}
- /**
+ /**
* Utility method to retrieve the inverse of the current mMatrix property.
* We cache the matrix to avoid recalculating it when transform properties
* have not changed.
@@ -15626,7 +15626,7 @@
*
* @attr ref android.R.styleable#View_layerType
*/
- public void setLayerType(int layerType, Paint paint) {
+ public void setLayerType(int layerType, @Nullable Paint paint) {
if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
@@ -15645,8 +15645,7 @@
}
mLayerType = layerType;
- final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
- mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
+ mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint;
mRenderNode.setLayerPaint(mLayerPaint);
// draw() behaves differently if we are on a layer, so we need to
@@ -15680,12 +15679,12 @@
*
* @see #setLayerType(int, android.graphics.Paint)
*/
- public void setLayerPaint(Paint paint) {
+ public void setLayerPaint(@Nullable Paint paint) {
int layerType = getLayerType();
if (layerType != LAYER_TYPE_NONE) {
- mLayerPaint = paint == null ? new Paint() : paint;
+ mLayerPaint = paint;
if (layerType == LAYER_TYPE_HARDWARE) {
- if (mRenderNode.setLayerPaint(mLayerPaint)) {
+ if (mRenderNode.setLayerPaint(paint)) {
invalidateViewProperty(false, false);
}
} else {
@@ -16855,7 +16854,7 @@
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
} else {
// use layer paint to draw the bitmap, merging the two alphas, but also restore
- int layerPaintAlpha = mLayerPaint.getAlpha();
+ int layerPaintAlpha = mLayerPaint != null ? mLayerPaint.getAlpha() : 255;
mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
mLayerPaint.setAlpha(layerPaintAlpha);
@@ -22187,7 +22186,7 @@
/**
* @hide
*/
- public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) {
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) {
// Do nothing.
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index da7799c..7c06577 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3287,6 +3287,7 @@
private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
+ private final static int MSG_FINISH_INPUT_CONNECTION = 12;
private final static int MSG_CHECK_FOCUS = 13;
private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
private final static int MSG_DISPATCH_DRAG_EVENT = 15;
@@ -3326,6 +3327,8 @@
return "MSG_DISPATCH_GET_NEW_SURFACE";
case MSG_DISPATCH_KEY_FROM_IME:
return "MSG_DISPATCH_KEY_FROM_IME";
+ case MSG_FINISH_INPUT_CONNECTION:
+ return "MSG_FINISH_INPUT_CONNECTION";
case MSG_CHECK_FOCUS:
return "MSG_CHECK_FOCUS";
case MSG_CLOSE_SYSTEM_DIALOGS:
@@ -3546,6 +3549,12 @@
}
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
+ case MSG_FINISH_INPUT_CONNECTION: {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.reportFinishInputConnection((InputConnection)msg.obj);
+ }
+ } break;
case MSG_CHECK_FOCUS: {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
@@ -3585,8 +3594,9 @@
handleDispatchWindowShown();
} break;
case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
- IResultReceiver receiver = (IResultReceiver) msg.obj;
- handleRequestKeyboardShortcuts(receiver);
+ final IResultReceiver receiver = (IResultReceiver) msg.obj;
+ final int deviceId = msg.arg1;
+ handleRequestKeyboardShortcuts(receiver, deviceId);
} break;
case MSG_UPDATE_POINTER_ICON: {
MotionEvent event = (MotionEvent) msg.obj;
@@ -5507,11 +5517,11 @@
mAttachInfo.mTreeObserver.dispatchOnWindowShown();
}
- public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
+ public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Bundle data = new Bundle();
ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
if (mView != null) {
- mView.requestKeyboardShortcuts(list);
+ mView.requestKeyboardShortcuts(list, deviceId);
}
data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
try {
@@ -5855,6 +5865,11 @@
}
}
+ public void dispatchFinishInputConnection(InputConnection connection) {
+ Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
+ mHandler.sendMessage(msg);
+ }
+
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Configuration newConfig, Rect backDropFrame, boolean forceLayout,
@@ -6468,8 +6483,9 @@
}
}
- public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
- mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
+ public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+ mHandler.obtainMessage(
+ MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
}
/**
@@ -7046,11 +7062,11 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
- ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
- }
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+ ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
+ }
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 63f3744..36ee3e6 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -565,9 +565,10 @@
*
* @param data The data list to populate with shortcuts.
* @param menu The current menu, which may be null.
+ * @param deviceId The id for the connected device the shortcuts should be provided for.
*/
default public void onProvideKeyboardShortcuts(
- List<KeyboardShortcutGroup> data, @Nullable Menu menu) { };
+ List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { };
}
/** @hide */
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index bed74e9..8f2d2e1 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -154,8 +154,9 @@
}
@Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- mWrapped.onProvideKeyboardShortcuts(data, menu);
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
+ mWrapped.onProvideKeyboardShortcuts(data, menu, deviceId);
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 17f1991..03dcf99 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -158,7 +158,7 @@
*
* @hide
*/
- public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver);
+ public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver, int deviceId);
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6e11671..f8c7d68 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -125,7 +125,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) {
+ public void requestAppKeyboardShortcuts(
+ final KeyboardShortcutsReceiver receiver, int deviceId) {
IResultReceiver resultReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
@@ -136,7 +137,7 @@
};
try {
WindowManagerGlobal.getWindowManagerService()
- .requestAppKeyboardShortcuts(resultReceiver);
+ .requestAppKeyboardShortcuts(resultReceiver, deviceId);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a3c49c5..6a830f8 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -158,8 +158,8 @@
*
* @hide
*/
- public void reportFinish() {
- // Intentionally empty
+ protected void reportFinish() {
+ // Intentionaly empty
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4bb0c3c..cf5cc3e 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -317,6 +317,7 @@
/**
* The InputConnection that was last retrieved from the served view.
*/
+ InputConnection mServedInputConnection;
ControlledInputConnectionWrapper mServedInputConnectionWrapper;
/**
* The completions that were last provided by the served view.
@@ -497,7 +498,7 @@
// from a thread that created mServedView. That could happen
// the current activity is running in the system process.
// In that case, we really should not call
- // mServedInputConnectionWrapper.finishComposingText().
+ // mServedInputConnection.finishComposingText.
if (checkFocusNoStartInput(mHasBeenInactive, false)) {
final int reason = active ?
InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
@@ -531,25 +532,22 @@
private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
private final InputMethodManager mParentInputMethodManager;
+ private boolean mActive;
public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
final InputMethodManager inputMethodManager) {
super(mainLooper, conn);
mParentInputMethodManager = inputMethodManager;
+ mActive = true;
}
@Override
public boolean isActive() {
- return mParentInputMethodManager.mActive && !isFinished();
+ return mParentInputMethodManager.mActive && mActive;
}
void deactivate() {
- if (isFinished()) {
- // This is a small performance optimization. Still only the 1st call of
- // reportFinish() will take effect.
- return;
- }
- reportFinish();
+ mActive = false;
}
@Override
@@ -564,9 +562,7 @@
@Override
public String toString() {
- return "ControlledInputConnectionWrapper{"
- + "connection=" + getInputConnection()
- + " finished=" + isFinished()
+ return "ControlledInputConnectionWrapper{mActive=" + mActive
+ " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
+ "}";
}
@@ -784,8 +780,7 @@
*/
public boolean isAcceptingText() {
checkFocus();
- return mServedInputConnectionWrapper != null &&
- mServedInputConnectionWrapper.getInputConnection() != null;
+ return mServedInputConnection != null;
}
/**
@@ -820,6 +815,7 @@
*/
void clearConnectionLocked() {
mCurrentTextBoxAttribute = null;
+ mServedInputConnection = null;
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.deactivate();
mServedInputConnectionWrapper = null;
@@ -840,6 +836,7 @@
throw e.rethrowFromSystemServer();
}
}
+ notifyInputConnectionFinished();
mServedView = null;
mCompletions = null;
mServedConnecting = false;
@@ -847,6 +844,37 @@
}
}
+ /**
+ * Notifies the served view that the current InputConnection will no longer be used.
+ */
+ private void notifyInputConnectionFinished() {
+ if (mServedView != null && mServedInputConnection != null) {
+ // We need to tell the previously served view that it is no
+ // longer the input target, so it can reset its state. Schedule
+ // this call on its window's Handler so it will be on the correct
+ // thread and outside of our lock.
+ ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
+ if (viewRootImpl != null) {
+ // This will result in a call to reportFinishInputConnection() below.
+ viewRootImpl.dispatchFinishInputConnection(mServedInputConnection);
+ }
+ }
+ }
+
+ /**
+ * Called from the FINISH_INPUT_CONNECTION message above.
+ * @hide
+ */
+ public void reportFinishInputConnection(InputConnection ic) {
+ if (mServedInputConnection != ic) {
+ ic.finishComposingText();
+ // To avoid modifying the public InputConnection interface
+ if (ic instanceof BaseInputConnection) {
+ ((BaseInputConnection) ic).reportFinish();
+ }
+ }
+ }
+
public void displayCompletions(View view, CompletionInfo[] completions) {
checkFocus();
synchronized (mH) {
@@ -1212,10 +1240,9 @@
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.deactivate();
- mServedInputConnectionWrapper = null;
- }
+ // Notify the served view that its previous input connection is finished
+ notifyInputConnectionFinished();
+ mServedInputConnection = ic;
ControlledInputConnectionWrapper servedContext;
final int missingMethodFlags;
if (ic != null) {
@@ -1240,6 +1267,9 @@
servedContext = null;
missingMethodFlags = 0;
}
+ if (mServedInputConnectionWrapper != null) {
+ mServedInputConnectionWrapper.deactivate();
+ }
mServedInputConnectionWrapper = servedContext;
try {
@@ -1383,7 +1413,7 @@
return false;
}
- final ControlledInputConnectionWrapper ic;
+ InputConnection ic = null;
synchronized (mH) {
if (mServedView == mNextServedView && !forceNewFocus) {
return false;
@@ -1403,7 +1433,7 @@
return false;
}
- ic = mServedInputConnectionWrapper;
+ ic = mServedInputConnection;
mServedView = mNextServedView;
mCurrentTextBoxAttribute = null;
@@ -2252,7 +2282,7 @@
} else {
p.println(" mCurrentTextBoxAttribute: null");
}
- p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
+ p.println(" mServedInputConnection=" + mServedInputConnection);
p.println(" mCompletions=" + Arrays.toString(mCompletions));
p.println(" mCursorRect=" + mCursorRect);
p.println(" mCursorSelStart=" + mCursorSelStart
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index d1b5fc8..1c85351 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -129,8 +129,8 @@
*/
private static final int ANIMATION_STYLE_DEFAULT = -1;
- private final int[] mDrawingLocation = new int[2];
- private final int[] mScreenLocation = new int[2];
+ private final int[] mTmpDrawingLocation = new int[2];
+ private final int[] mTmpScreenLocation = new int[2];
private final Rect mTempRect = new Rect();
private Context mContext;
@@ -222,7 +222,7 @@
mDecorView.getLayoutParams();
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
- mAnchoredGravity));
+ p.width, p.height, mAnchoredGravity));
update(p.x, p.y, -1, -1, true);
}
}
@@ -1123,7 +1123,7 @@
TransitionManager.endTransitions(mDecorView);
- unregisterForViewTreeChanges();
+ detachFromAnchor();
mIsShowing = true;
mIsDropdown = false;
@@ -1206,7 +1206,7 @@
TransitionManager.endTransitions(mDecorView);
- registerForViewTreeChanges(anchor, xoff, yoff, gravity);
+ attachToAnchor(anchor, xoff, yoff, gravity);
mIsShowing = true;
mIsDropdown = true;
@@ -1214,7 +1214,8 @@
final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
preparePopup(p);
- final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity);
+ final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
+ p.width, p.height, gravity);
updateAboveAnchor(aboveAnchor);
invokePopup(p);
@@ -1494,120 +1495,130 @@
* to reclaim space. If scrolling is not possible or not enough, the popup
* window gets moved on top of the anchor.
* <p>
- * The height must have been set on the layout parameters prior to calling
- * this method.
+ * The results of positioning are placed in {@code outParams}.
*
* @param anchor the view on which the popup window must be anchored
- * @param p the layout parameters used to display the drop down
- * @param xoff horizontal offset used to adjust for background padding
- * @param yoff vertical offset used to adjust for background padding
+ * @param outParams the layout parameters used to display the drop down
+ * @param xOffset horizontal offset used to adjust for background padding
+ * @param yOffset vertical offset used to adjust for background padding
* @param gravity horizontal gravity specifying popup alignment
* @return true if the popup is translated upwards to fit on screen
*/
- private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff,
- int yoff, int gravity) {
+ private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
+ int xOffset, int yOffset, int width, int height, int gravity) {
final int anchorHeight = anchor.getHeight();
final int anchorWidth = anchor.getWidth();
if (mOverlapAnchor) {
- yoff -= anchorHeight;
+ yOffset -= anchorHeight;
}
- anchor.getLocationInWindow(mDrawingLocation);
- p.x = mDrawingLocation[0] + xoff;
- p.y = mDrawingLocation[1] + anchorHeight + yoff;
+ final int[] drawingLocation = mTmpDrawingLocation;
+ anchor.getLocationInWindow(drawingLocation);
+ outParams.x = drawingLocation[0] + xOffset;
+ outParams.y = drawingLocation[1] + anchorHeight + yOffset;
final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
& Gravity.HORIZONTAL_GRAVITY_MASK;
if (hgrav == Gravity.RIGHT) {
// Flip the location to align the right sides of the popup and
// anchor instead of left.
- p.x -= mPopupWidth - anchorWidth;
+ outParams.x -= width - anchorWidth;
}
- boolean onTop = false;
+ outParams.gravity = Gravity.LEFT | Gravity.TOP;
- p.gravity = Gravity.LEFT | Gravity.TOP;
+ final int[] screenLocation = mTmpScreenLocation;
+ anchor.getLocationOnScreen(screenLocation);
- anchor.getLocationOnScreen(mScreenLocation);
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
- final int screenY = mScreenLocation[1] + anchorHeight + yoff;
+ final boolean onTop;
+ final int screenY = screenLocation[1] + anchorHeight + yOffset;
final View root = anchor.getRootView();
- if (screenY + mPopupHeight > displayFrame.bottom
- || p.x + mPopupWidth - root.getWidth() > 0) {
+ if (screenY + height > displayFrame.bottom
+ || outParams.x + width - root.getWidth() > 0) {
// If the drop down disappears at the bottom of the screen, we try
// to scroll a parent scrollview or move the drop down back up on
// top of the edit box.
if (mAllowScrollingAnchorParent) {
final int scrollX = anchor.getScrollX();
final int scrollY = anchor.getScrollY();
- final Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
- scrollY + mPopupHeight + anchorHeight + yoff);
+ final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
+ scrollY + height + anchorHeight + yOffset);
anchor.requestRectangleOnScreen(r, true);
}
// Now we re-evaluate the space available, and decide from that
// whether the pop-up will go above or below the anchor.
- anchor.getLocationInWindow(mDrawingLocation);
- p.x = mDrawingLocation[0] + xoff;
- p.y = mDrawingLocation[1] + anchorHeight + yoff;
+ anchor.getLocationInWindow(drawingLocation);
+ outParams.x = drawingLocation[0] + xOffset;
+ outParams.y = drawingLocation[1] + anchorHeight + yOffset;
// Preserve the gravity adjustment.
if (hgrav == Gravity.RIGHT) {
- p.x -= mPopupWidth - anchorWidth;
+ outParams.x -= width - anchorWidth;
}
// Determine whether there is more space above or below the anchor.
- anchor.getLocationOnScreen(mScreenLocation);
- onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
- (mScreenLocation[1] - yoff - displayFrame.top);
+ anchor.getLocationOnScreen(screenLocation);
+ final int spaceBelow = displayFrame.bottom - screenLocation[1] - anchorHeight - yOffset;
+ final int spaceAbove = screenLocation[1] - yOffset - displayFrame.top;
+ onTop = spaceBelow < spaceAbove;
+
if (!mOverlapAnchor) {
if (onTop) {
- p.gravity = Gravity.LEFT | Gravity.BOTTOM;
- p.y = root.getHeight() - mDrawingLocation[1] + yoff;
+ outParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
+ outParams.y = root.getHeight() - drawingLocation[1] + yOffset;
} else {
- p.y = mDrawingLocation[1] + anchorHeight + yoff;
+ outParams.y = drawingLocation[1] + anchorHeight + yOffset;
}
}
+ } else {
+ onTop = false;
}
if (mClipToScreen) {
- final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
- final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
- p.x += winOffsetX;
- p.y += winOffsetY;
- final int displayFrameWidth = displayFrame.right - displayFrame.left;
- final int right = p.x + p.width;
+ final int winOffsetX = screenLocation[0] - drawingLocation[0];
+ final int winOffsetY = screenLocation[1] - drawingLocation[1];
+ outParams.x += winOffsetX;
+ outParams.y += winOffsetY;
+
+ final int right = outParams.x + width;
if (right > displayFrame.right) {
- p.x -= right - displayFrame.right;
+ outParams.x -= right - displayFrame.right;
}
- if (p.x < displayFrame.left) {
- p.x = displayFrame.left;
- p.width = Math.min(p.width, displayFrameWidth);
+ if (outParams.x < displayFrame.left) {
+ outParams.x = displayFrame.left;
+
+ final int displayFrameWidth = displayFrame.right - displayFrame.left;
+ width = Math.min(width, displayFrameWidth);
}
if (mOverlapAnchor) {
- final int bottom = p.y + p.height;
+ final int bottom = outParams.y + width;
if (bottom > displayFrame.bottom) {
- p.y -= bottom - displayFrame.bottom;
+ outParams.y -= bottom - displayFrame.bottom;
}
} else {
if (onTop) {
- final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+ final int popupTop = screenLocation[1] + yOffset - height;
if (popupTop < 0) {
- p.y += popupTop;
+ outParams.y += popupTop;
}
} else {
- p.y = Math.max(p.y, displayFrame.top);
+ outParams.y = Math.max(outParams.y, displayFrame.top);
}
}
- p.x -= winOffsetX;
- p.y -= winOffsetY;
+
+ outParams.x -= winOffsetX;
+ outParams.y -= winOffsetY;
}
- p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
+ outParams.width = width;
+ outParams.height = height;
+ outParams.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
return onTop;
}
@@ -1665,7 +1676,7 @@
anchor.getWindowVisibleDisplayFrame(displayFrame);
}
- final int[] anchorPos = mDrawingLocation;
+ final int[] anchorPos = mTmpDrawingLocation;
anchor.getLocationOnScreen(anchorPos);
final int bottomEdge = displayFrame.bottom;
@@ -1754,7 +1765,7 @@
}
// Clears the anchor view.
- unregisterForViewTreeChanges();
+ detachFromAnchor();
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss();
@@ -2018,43 +2029,40 @@
}
final WeakReference<View> oldAnchor = mAnchor;
+ final int gravity = mAnchoredGravity;
+
final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
- registerForViewTreeChanges(anchor, xoff, yoff, mAnchoredGravity);
+ attachToAnchor(anchor, xoff, yoff, gravity);
} else if (needsUpdate) {
// No need to register again if this is a DropDown, showAsDropDown already did.
mAnchorXoff = xoff;
mAnchorYoff = yoff;
}
- final WindowManager.LayoutParams p =
- (WindowManager.LayoutParams) mDecorView.getLayoutParams();
+ final LayoutParams p = (LayoutParams) mDecorView.getLayoutParams();
+ final int oldGravity = p.gravity;
+ final int oldWidth = p.width;
+ final int oldHeight = p.height;
+ final int oldX = p.x;
+ final int oldY = p.y;
if (updateDimension) {
if (width == -1) {
width = mPopupWidth;
- } else {
- mPopupWidth = width;
- p.width = width;
}
if (height == -1) {
height = mPopupHeight;
- } else {
- mPopupHeight = height;
- p.height = height;
}
}
- final int x = p.x;
- final int y = p.y;
- if (updateLocation) {
- updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, mAnchoredGravity));
- } else {
- updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
- mAnchoredGravity));
- }
+ final boolean aboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+ width, height, gravity);
+ updateAboveAnchor(aboveAnchor);
- update(p.x, p.y, width, height, x != p.x || y != p.y);
+ final boolean paramsChanged = oldGravity != p.gravity || oldX != p.x || oldY != p.y
+ || oldWidth != p.width || oldHeight != p.height;
+ update(p.x, p.y, p.width, p.height, paramsChanged);
}
/**
@@ -2067,7 +2075,7 @@
public void onDismiss();
}
- private void unregisterForViewTreeChanges() {
+ private void detachFromAnchor() {
final View anchor = mAnchor != null ? mAnchor.get() : null;
if (anchor != null) {
final ViewTreeObserver vto = anchor.getViewTreeObserver();
@@ -2084,8 +2092,8 @@
mIsAnchorRootAttached = false;
}
- private void registerForViewTreeChanges(View anchor, int xoff, int yoff, int gravity) {
- unregisterForViewTreeChanges();
+ private void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+ detachFromAnchor();
final ViewTreeObserver vto = anchor.getViewTreeObserver();
if (vto != null) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index fbd8fb5..bdf2a21 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2070,10 +2070,10 @@
* @hide
*/
@Override
- public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list, int deviceId) {
final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) {
- mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
+ mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu, deviceId);
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ab918c8..530e00c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -111,6 +111,6 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
}
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 02b9db3..3be15f3 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -16,10 +16,6 @@
package com.android.internal.view;
-import com.android.internal.annotations.GuardedBy;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -27,7 +23,6 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedTextRequest;
@@ -61,16 +56,11 @@
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
- private static final int DO_REPORT_FINISH = 150;
- @NonNull
- private final WeakReference<InputConnection> mInputConnection;
+ private WeakReference<InputConnection> mInputConnection;
private Looper mMainLooper;
private Handler mH;
- private Object mLock = new Object();
- @GuardedBy("mLock")
- private boolean mFinished = false;
static class SomeArgs {
Object arg1;
@@ -96,17 +86,6 @@
mH = new MyHandler(mMainLooper);
}
- @Nullable
- public InputConnection getInputConnection() {
- return mInputConnection.get();
- }
-
- protected boolean isFinished() {
- synchronized (mLock) {
- return mFinished;
- }
- }
-
abstract protected boolean isActive();
/**
@@ -219,10 +198,6 @@
seq, callback));
}
- public void reportFinish() {
- dispatchMessage(obtainMessage(DO_REPORT_FINISH));
- }
-
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -235,7 +210,7 @@
mH.sendMessage(msg);
}
-
+
void executeMessage(Message msg) {
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
@@ -498,36 +473,6 @@
}
return;
}
- case DO_REPORT_FINISH: {
- // Note that we do not need to worry about race condition here, because 1) mFinished
- // is updated only inside this block, and 2) the code here is running on a Handler
- // hence we assume multiple DO_REPORT_FINISH messages will not be handled at the
- // same time.
- if (isFinished()) {
- return;
- }
- try {
- InputConnection ic = mInputConnection.get();
- // Note we do NOT check isActive() here, because this is safe
- // for an IME to call at any time, and we need to allow it
- // through to clean up our state after the IME has switched to
- // another client.
- if (ic == null) {
- return;
- }
- ic.finishComposingText();
- // TODO: Make reportFinish() public method of InputConnection to remove this
- // check.
- if (ic instanceof BaseInputConnection) {
- ((BaseInputConnection) ic).reportFinish();
- }
- } finally {
- synchronized (mLock) {
- mFinished = true;
- }
- }
- return;
- }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index a96b5a0..f211ff2 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -83,11 +83,8 @@
return false;
}
- /**
- * @hide
- */
@Override
- public void reportFinish() {
+ protected void reportFinish() {
super.reportFinish();
synchronized(this) {
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 809e525..ba6d30a 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -51,7 +51,7 @@
<LinearLayout
android:id="@+id/media_actions"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginStart="10dp"
android:layout_marginBottom="12dp"
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/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 1966313..7519627 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -291,9 +291,6 @@
@Override
public void onActionModeFinished(ActionMode mode) {}
-
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {}
}
private static final class MockActionModeCallback implements ActionMode.Callback {
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
index 0416159..2848949 100644
--- a/graphics/java/android/graphics/PathMeasure.java
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -112,7 +112,7 @@
* Given a start and stop distance, return in dst the intervening
* segment(s). If the segment is zero-length, return false, else return
* true. startD and stopD are pinned to legal values (0..getLength()).
- * If startD <= stopD then return false (and leave dst untouched).
+ * If startD >= stopD then return false (and leave dst untouched).
* Begin the segment with a moveTo if startWithMoveTo is true.
*
* <p>On {@link android.os.Build.VERSION_CODES#KITKAT} and earlier
@@ -121,6 +121,19 @@
* such as <code>dst.rLineTo(0, 0)</code>.</p>
*/
public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) {
+ // Skia used to enforce this as part of it's API, but has since relaxed that restriction
+ // so to maintain consistency in our API we enforce the preconditions here.
+ float length = getLength();
+ if (startD < 0) {
+ startD = 0;
+ }
+ if (stopD > length) {
+ stopD = length;
+ }
+ if (startD >= stopD) {
+ return false;
+ }
+
dst.isSimplePath = false;
return native_getSegment(native_instance, startD, stopD, dst.ni(), startWithMoveTo);
}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 6ab5110..ca72673 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -23,6 +23,9 @@
#include <tests/common/TestUtils.h>
#include <utils/Color.h>
+#include <SkGradientShader.h>
+#include <SkShader.h>
+
namespace android {
namespace uirenderer {
@@ -599,6 +602,45 @@
EXPECT_NE(&paint, ops[3]->paint);
}
+TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(bitmap,
+ SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode));
+ paint.setShader(shader);
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
+ auto& bitmaps = dl->getBitmapResources();
+ EXPECT_EQ(1u, bitmaps.size());
+}
+
+TEST(RecordingCanvas, refBitmapInShader_composeShader) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkAutoTUnref<SkShader> shader1(SkShader::CreateBitmapShader(bitmap,
+ SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode));
+
+ SkPoint center;
+ center.set(50, 50);
+ SkColor colors[2];
+ colors[0] = Color::Black;
+ colors[1] = Color::White;
+ SkAutoTUnref<SkShader> shader2(SkGradientShader::CreateRadial(center, 50, colors, nullptr, 2,
+ SkShader::TileMode::kRepeat_TileMode));
+
+ SkAutoTUnref<SkShader> composeShader(SkShader::CreateComposeShader(shader1, shader2,
+ SkXfermode::Mode::kMultiply_Mode));
+ paint.setShader(composeShader);
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
+ auto& bitmaps = dl->getBitmapResources();
+ EXPECT_EQ(1u, bitmaps.size());
+}
+
TEST(RecordingCanvas, drawText) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Paint paint;
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/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 612a147..97ef6d8 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1689,19 +1689,20 @@
public abstract void onTune(Uri channelUri);
/**
- * Called when the application requests to tune to a given channel for TV program recording.
+ * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific
+ * features that are only known between certain TV inputs and their clients.
*
* <p>The application may call this method before starting or after stopping recording, but
* not during recording.
*
- * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+ * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or
* {@link #notifyError(int)} otherwise.
*
* @param channelUri The URI of a channel.
- * @param params Extra parameters.
- * @hide
+ * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+ * name, i.e. prefixed with a package name you own, so that different developers
+ * will not create conflicting keys.
*/
- @SystemApi
public void onTune(Uri channelUri, Bundle params) {
onTune(channelUri);
}
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index da1002d..a5ff29f 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -91,22 +91,23 @@
* Tunes to a given channel for TV program recording. The first tune request will create a new
* recording session for the corresponding TV input and establish a connection between the
* application and the session. If recording has already started in the current recording
- * session, this method throws an exception.
+ * session, this method throws an exception. This can be used to provide domain-specific
+ * features that are only known between certain client and their TV inputs.
*
* <p>The application may call this method before starting or after stopping recording, but not
* during recording.
*
* <p>The recording session will respond by calling
- * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+ * {@link RecordingCallback#onTuned(Uri)} if the tune request was fulfilled, or
* {@link RecordingCallback#onError(int)} otherwise.
*
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel.
- * @param params Extra parameters.
+ * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
+ * name, i.e. prefixed with a package name you own, so that different developers will
+ * not create conflicting keys.
* @throws IllegalStateException If recording is already started.
- * @hide
*/
- @SystemApi
public void tune(String inputId, Uri channelUri, Bundle params) {
if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
if (TextUtils.isEmpty(inputId)) {
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/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index aea8585..f21fd88 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -27,7 +27,8 @@
<activity
android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
android:label="@string/action_bar_label"
- android:theme="@style/AppTheme" >
+ android:theme="@style/AppTheme"
+ android:configChanges="keyboardHidden|orientation|screenSize" >
<intent-filter>
<action android:name="android.net.conn.CAPTIVE_PORTAL"/>
<category android:name="android.intent.category.DEFAULT"/>
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/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 18160ff..d2b4d1b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -1041,7 +1041,9 @@
try {
in = mStatePersistFile.openRead();
} catch (FileNotFoundException e) {
- Log.i(LOG_TAG, "No existing print spooler state.");
+ if (DEBUG_PERSISTENCE) {
+ Log.d(LOG_TAG, "No existing print spooler state.");
+ }
return;
}
try {
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 3b818c8..0e3e0d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -60,7 +60,7 @@
public class StorageMeasurement {
private static final String TAG = "StorageMeasurement";
- private static final boolean LOCAL_LOGV = true;
+ private static final boolean LOCAL_LOGV = false;
static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index c9582ea..c131fa5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -409,10 +409,11 @@
final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
if (mProcesses.indexOfKey(id) >= 0) {
+ // BUGREPORT_STARTED intent was already received; ignore it.
Log.w(TAG, "ID " + id + " already watched");
- } else {
- mProcesses.put(info.id, info);
+ return true;
}
+ mProcesses.put(info.id, info);
// Take initial screenshot.
takeScreenshot(id, false);
updateProgress(info);
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/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 6d8b476..51efbf0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -36,12 +36,12 @@
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
+import static android.provider.Settings.ACTION_VPN_SETTINGS;
+
public class QSFooter implements OnClickListener, DialogInterface.OnClickListener {
protected static final String TAG = "QSFooter";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
-
private final View mRootView;
private final TextView mFooterText;
private final ImageView mFooterIcon;
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/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index f67f099..043510e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -34,7 +34,7 @@
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// Enables the task affiliations
- public static final boolean EnableAffiliatedTaskGroups = true;
+ public static final boolean EnableAffiliatedTaskGroups = false;
// TODO: To be repurposed
public static final boolean EnableStackActionButton = false;
// Overrides the Tuner flags and enables the timeout
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 58216b0..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);
@@ -818,6 +823,7 @@
protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
boolean isTopTaskHome, boolean animate) {
RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
// In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
// should always preload the tasks now. If we are dragging in recents, reload them as
@@ -829,7 +835,10 @@
if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
}
+
TaskStack stack = sInstanceLoadPlan.getTaskStack();
+ boolean hasRecentTasks = stack.getTaskCount() > 0;
+ boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
// Update the header bar if necessary
updateHeaderBarLayout(stack);
@@ -838,22 +847,31 @@
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
mDummyStackView.computeStackVisibilityReport();
+ // Update the launch state
+ launchState.launchedFromHome = false;
+ launchState.launchedFromApp = mLaunchedWhileDocking;
+ launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+ launchState.launchedFromAppDocked = mLaunchedWhileDocking;
+ launchState.launchedWithAltTab = mTriggeredFromAltTab;
+ launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+ launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
+ launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
+ launchState.launchedHasConfigurationChanged = false;
+ launchState.launchedViaDragGesture = mDraggingInRecents;
+ launchState.launchedWhileDocking = mLaunchedWhileDocking;
+
if (!animate) {
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
- startRecentsActivity(topTask, opts, false /* fromHome */, false /* fromThumbnail*/,
- stackVr);
+ startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
return;
}
- boolean hasRecentTasks = stack.getTaskCount() > 0;
- boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
-
if (useThumbnailTransition) {
+ launchState.launchedFromApp = true;
+
// Try starting with a thumbnail transition
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView);
if (opts != null) {
- startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */,
- stackVr);
+ startRecentsActivity(opts);
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
@@ -861,13 +879,14 @@
}
if (!useThumbnailTransition) {
+ launchState.launchedFromHome = true;
+
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition
ActivityOptions opts = hasRecentTasks
? getHomeTransitionActivityOptions()
: getUnknownTransitionActivityOptions();
- startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromThumbnail */,
- stackVr);
+ startRecentsActivity(opts);
}
mLastToggleTime = SystemClock.elapsedRealtime();
}
@@ -875,24 +894,7 @@
/**
* Starts the recents activity.
*/
- private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, boolean fromHome, boolean fromThumbnail,
- TaskStackLayoutAlgorithm.VisibilityReport vr) {
- // Update the configuration based on the launch options
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- launchState.launchedFromHome = fromHome;
- launchState.launchedFromApp = fromThumbnail || mLaunchedWhileDocking;
- launchState.launchedFromAppDocked = mLaunchedWhileDocking;
- launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
- launchState.launchedWithAltTab = mTriggeredFromAltTab;
- launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
- launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
- launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
- launchState.launchedHasConfigurationChanged = false;
- launchState.launchedViaDragGesture = mDraggingInRecents;
- launchState.launchedWhileDocking = mLaunchedWhileDocking;
-
+ private void startRecentsActivity(ActivityOptions opts) {
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
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 6b3eab8..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;
}
/**
@@ -1025,8 +1030,9 @@
return dividerWindowWidth - 2 * dividerInsets;
}
- public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
- mWm.requestAppKeyboardShortcuts(receiver);
+ public void requestKeyboardShortcuts(
+ Context context, KeyboardShortcutsReceiver receiver, int deviceId) {
+ mWm.requestAppKeyboardShortcuts(receiver, deviceId);
}
public void getStableInsets(Rect outStableInsets) {
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 c863471..76ca6ca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -160,8 +160,15 @@
long parentTaskLastActiveTime = parentTask != null
? parentTask.lastActiveTime
: prevLastActiveTime;
- t.lastActiveTime = parentTaskLastActiveTime +
- affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
+ if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
+ t.lastActiveTime = parentTaskLastActiveTime +
+ affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
+ } else {
+ if (t.lastActiveTime == 0) {
+ t.lastActiveTime = parentTaskLastActiveTime -
+ affiliatedTaskCounts.get(t.affiliatedTaskId, 0) - 1;
+ }
+ }
}
// Compose the task key
@@ -201,7 +208,6 @@
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
affiliatedTasks.put(taskKey.id, taskKey);
-
prevLastActiveTime = t.lastActiveTime;
}
if (newLastStackActiveTime != -1) {
@@ -240,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/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 930e2d0..a930791 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -429,12 +429,14 @@
mStackTaskList.setFilter(new TaskFilter() {
@Override
public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
- if (t.isAffiliatedTask()) {
- // If this task is affiliated with another parent in the stack, then the
- // historical state of this task depends on the state of the parent task
- Task parentTask = taskIdMap.get(t.affiliationTaskId);
- if (parentTask != null) {
- t = parentTask;
+ if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
+ if (t.isAffiliatedTask()) {
+ // If this task is affiliated with another parent in the stack, then the
+ // historical state of this task depends on the state of the parent task
+ Task parentTask = taskIdMap.get(t.affiliationTaskId);
+ if (parentTask != null) {
+ t = parentTask;
+ }
}
}
return t.isStackTask;
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/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 9e5558a..8fe60a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -248,7 +248,7 @@
result.add(systemGroup);
showKeyboardShortcutsDialog(result);
}
- });
+ }, deviceId);
} else {
dismissKeyboardShortcutsDialog();
}
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/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index b57e14e..4749417 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -684,13 +684,18 @@
public long SMS_TEMP_APP_WHITELIST_DURATION;
private final ContentResolver mResolver;
+ private final boolean mHasWatch;
private final KeyValueListParser mParser = new KeyValueListParser(',');
public Constants(Handler handler, ContentResolver resolver) {
super(handler);
mResolver = resolver;
- mResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
+ mHasWatch = getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH);
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ mHasWatch ? Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH
+ : Settings.Global.DEVICE_IDLE_CONSTANTS),
+ false, this);
updateConstants();
}
@@ -703,7 +708,8 @@
synchronized (DeviceIdleController.this) {
try {
mParser.setString(Settings.Global.getString(mResolver,
- Settings.Global.DEVICE_IDLE_CONSTANTS));
+ mHasWatch ? Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH
+ : Settings.Global.DEVICE_IDLE_CONSTANTS));
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
@@ -724,8 +730,9 @@
MIN_DEEP_MAINTENANCE_TIME = mParser.getLong(
KEY_MIN_DEEP_MAINTENANCE_TIME,
!COMPRESS_TIME ? 30 * 1000L : 5 * 1000L);
+ long inactiveTimeoutDefault = (mHasWatch ? 15 : 30) * 60 * 1000L;
INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
- !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ !COMPRESS_TIME ? inactiveTimeoutDefault : (inactiveTimeoutDefault / 10));
SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
!DEBUG ? 4 * 60 * 1000L : 60 * 1000L);
LOCATING_TIMEOUT = mParser.getLong(KEY_LOCATING_TIMEOUT,
@@ -733,8 +740,10 @@
LOCATION_ACCURACY = mParser.getFloat(KEY_LOCATION_ACCURACY, 20);
MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+ long idleAfterInactiveTimeout = (mHasWatch ? 15 : 30) * 60 * 1000L;
IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
- !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ !COMPRESS_TIME ? idleAfterInactiveTimeout
+ : (idleAfterInactiveTimeout / 10));
IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
!COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 575d99e..23cf64a 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -23,6 +23,8 @@
import android.os.CpuUsageInfo;
import android.os.IHardwarePropertiesManager;
import android.os.Process;
+import android.os.UserHandle;
+import com.android.server.vr.VrManagerInternal;
import java.util.Arrays;
@@ -78,14 +80,15 @@
*
* @param callingPackage The calling package name.
*
- * @throws SecurityException if a non profile or device owner or system tries to retrieve
- * information provided by the service.
+ * @throws SecurityException if something other than the profile or device owner, or the
+ * current VR service tries to retrieve information provided by this service.
*/
private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
throws SecurityException {
final PackageManager pm = mContext.getPackageManager();
+ int uid = 0;
try {
- final int uid = pm.getPackageUid(callingPackage, 0);
+ uid = pm.getPackageUid(callingPackage, 0);
if (Binder.getCallingUid() != uid) {
throw new SecurityException("The caller has faked the package name.");
}
@@ -93,10 +96,13 @@
throw new SecurityException("The caller has faked the package name.");
}
+ final int userId = UserHandle.getUserId(uid);
+ final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)
- && Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("The caller is not a device or profile owner or system.");
+ && !vrService.isCurrentVrListener(callingPackage, userId)) {
+ throw new SecurityException("The caller is not a device or profile owner or bound "
+ + "VrListenerService.");
}
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 548b662..c1a352c 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -513,6 +513,28 @@
}
}
+ // Sync the state of the given chain with the native daemon.
+ private void syncFirewallChainLocked(int chain, SparseIntArray uidFirewallRules, String name) {
+ int size = uidFirewallRules.size();
+ if (size > 0) {
+ // Make a copy of the current rules, and then clear them. This is because
+ // setFirewallUidRuleInternal only pushes down rules to the native daemon if they are
+ // different from the current rules stored in the mUidFirewall*Rules array for the
+ // specified chain. If we don't clear the rules, setFirewallUidRuleInternal will do
+ // nothing.
+ final SparseIntArray rules = uidFirewallRules.clone();
+ uidFirewallRules.clear();
+
+ // Now push the rules. setFirewallUidRuleInternal will push each of these down to the
+ // native daemon, and also add them to the mUidFirewall*Rules array for the specified
+ // chain.
+ if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall " + name + "UID rules");
+ for (int i = 0; i < rules.size(); i++) {
+ setFirewallUidRuleInternal(chain, rules.keyAt(i), rules.valueAt(i));
+ }
+ }
+ }
+
/**
* Prepare native daemon once connected, enabling modules and pushing any
* existing in-memory rules.
@@ -603,55 +625,18 @@
setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
- size = mUidFirewallRules.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
- final SparseIntArray uidFirewallRules = mUidFirewallRules;
- mUidFirewallRules = new SparseIntArray();
- for (int i = 0; i < uidFirewallRules.size(); i++) {
- setFirewallUidRuleInternal(FIREWALL_CHAIN_NONE, uidFirewallRules.keyAt(i),
- uidFirewallRules.valueAt(i));
- }
- }
+ syncFirewallChainLocked(FIREWALL_CHAIN_NONE, mUidFirewallRules, "");
+ syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, mUidFirewallStandbyRules, "standby ");
+ syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mUidFirewallDozableRules, "dozable ");
+ syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, mUidFirewallPowerSaveRules,
+ "powersave ");
- size = mUidFirewallStandbyRules.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
- final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules;
- mUidFirewallStandbyRules = new SparseIntArray();
- for (int i = 0; i < uidFirewallRules.size(); i++) {
- setFirewallUidRuleInternal(FIREWALL_CHAIN_STANDBY, uidFirewallRules.keyAt(i),
- uidFirewallRules.valueAt(i));
- }
- }
if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
}
-
- size = mUidFirewallDozableRules.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
- final SparseIntArray uidFirewallRules = mUidFirewallDozableRules;
- mUidFirewallDozableRules = new SparseIntArray();
- for (int i = 0; i < uidFirewallRules.size(); i++) {
- setFirewallUidRuleInternal(FIREWALL_CHAIN_DOZABLE, uidFirewallRules.keyAt(i),
- uidFirewallRules.valueAt(i));
- }
- }
if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
}
-
- size = mUidFirewallPowerSaveRules.size();
- if (size > 0) {
- Slog.d(TAG, "Pushing " + size + " active firewall powersave UID rules");
- final SparseIntArray uidFirewallRules = mUidFirewallPowerSaveRules;
- mUidFirewallPowerSaveRules = new SparseIntArray();
- for (int i = 0; i < uidFirewallRules.size(); i++) {
- setFirewallUidRuleInternal(FIREWALL_CHAIN_POWERSAVE, uidFirewallRules.keyAt(i),
- uidFirewallRules.valueAt(i));
- }
- }
if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c1ec71c..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;
@@ -3013,7 +3015,7 @@
if (!app.killed) {
Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
Process.killProcessQuiet(app.pid);
- killProcessGroup(app.info.uid, app.pid);
+ killProcessGroup(app.uid, app.pid);
}
if (lrui <= mLruProcessActivityStart) {
mLruProcessActivityStart--;
@@ -3386,7 +3388,7 @@
// clean it up now.
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
checkTime(startTime, "startProcess: bad proc running, killing");
- killProcessGroup(app.info.uid, app.pid);
+ killProcessGroup(app.uid, app.pid);
handleAppDiedLocked(app, true, true);
checkTime(startTime, "startProcess: done killing old proc");
}
@@ -5021,7 +5023,7 @@
if (!fromBinderDied) {
Process.killProcessQuiet(pid);
}
- killProcessGroup(app.info.uid, pid);
+ killProcessGroup(app.uid, pid);
app.killed = true;
}
@@ -11422,18 +11424,16 @@
try {
final int currentUserId = mUserController.getCurrentUserIdLocked();
// Get the focused task before launching launcher.
- final int taskId = (mFocusedActivity == null)
- ? -1 : mFocusedActivity.task.taskId;
- startHomeActivityLocked(currentUserId, "notifyLockedProfile");
+
if (mUserController.isLockScreenDisabled(currentUserId)) {
- // If there is no device lock, we first go to launcher and then resume the
- // original task. Work challenge will be shown because we intercepted
- // startActivityFromRecentsInner and the reason why we switch to home stack
- // first is to prevent pressing back button brings user back to the work
- // app.
- if (taskId != -1) {
- startActivityFromRecentsInner(taskId, null);
+ // If there is no device lock, we will show the profile's credential page.
+ // startActivityFromRecentsInner is intercepted and will forward user to it.
+ if (mFocusedActivity != null) {
+ startActivityFromRecentsInner(mFocusedActivity.task.taskId, null);
}
+ } else {
+ // Showing launcher to avoid user entering credential twice.
+ startHomeActivityLocked(currentUserId, "notifyLockedProfile");
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12592,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 26eaa8a..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);
@@ -1980,7 +1980,9 @@
if (next == null) {
// There are no more activities!
final String reason = "noMoreActivities";
- if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
+ final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
+ ? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
+ if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
// Try to move focus to the next visible stack with a running activity if this
// stack is not covering the entire screen.
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
@@ -1993,8 +1995,6 @@
"resumeTopActivityLocked: No more activities go home");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
// Only resume home if on home display
- final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
- HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
@@ -3004,16 +3004,18 @@
} else {
final TaskRecord task = r.task;
if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+ final int taskToReturnTo = task.getTaskToReturnTo();
+
// For non-fullscreen stack, we want to move the focus to the next visible
// stack to prevent the home screen from moving to the top and obscuring
// other visible stacks.
- if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
+ if (!mFullscreen
+ && adjustFocusToNextFocusableStackLocked(taskToReturnTo, myReason)) {
return;
}
// Move the home stack to the top if this stack is fullscreen or there is no
// other visible stack.
- if (mStackSupervisor.moveHomeStackTaskToTop(
- task.getTaskToReturnTo(), myReason)) {
+ if (mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, myReason)) {
// Activity focus was already adjusted. Nothing else to do...
return;
}
@@ -3024,12 +3026,16 @@
mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
}
- private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+ private boolean adjustFocusToNextFocusableStackLocked(int taskToReturnTo, String reason) {
final ActivityStack stack = getNextFocusableStackLocked();
final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
}
+
+ if (stack.isHomeStack()) {
+ return mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, reason);
+ }
return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
}
@@ -4843,7 +4849,9 @@
// We only need to adjust focused stack if this stack is in focus.
if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
String myReason = reason + " leftTaskHistoryEmpty";
- if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
+ if (mFullscreen
+ || !adjustFocusToNextFocusableStackLocked(
+ task.getTaskToReturnTo(), myReason)) {
mStackSupervisor.moveHomeStackToFront(myReason);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 13d90e3..76dfd01 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -26,6 +26,7 @@
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
import android.app.KeyguardManager;
@@ -192,14 +193,14 @@
Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
new String[]{ resolvedType },
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
- final int flags = intent.getFlags();
final KeyguardManager km = (KeyguardManager) mService.mContext
.getSystemService(KEYGUARD_SERVICE);
final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
if (newIntent == null) {
return null;
}
- newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+ FLAG_ACTIVITY_TASK_ON_HOME);
newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
return newIntent;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 71a1f97..ffa3b5b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1170,7 +1170,8 @@
}
if (useCheckinFormat) {
- List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
+ List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
if (isRealCheckin) {
// For a real checkin, first we want to prefer to use the last complete checkin
// file if there is one.
diff --git a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
index 39c6ce6..9fb51c1 100644
--- a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
+++ b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
@@ -122,7 +122,8 @@
// Battery Stats stores the GPS sensors with a bogus key in this API. Pull it out
// as a separate metric here so as to not expose that in the API.
if (sensorId == BatteryStats.Uid.Sensor.GPS) {
- addTimer(uidWriter, UidHealthStats.TIMER_GPS_SENSOR, sensors.valueAt(i).getSensorTime());
+ addTimer(uidWriter, UidHealthStats.TIMER_GPS_SENSOR,
+ sensors.valueAt(i).getSensorTime());
} else {
addTimers(uidWriter, UidHealthStats.TIMERS_SENSORS, Integer.toString(sensorId),
sensors.valueAt(i).getSensorTime());
@@ -131,7 +132,7 @@
// STATS_PIDS
pids = uid.getPidStats();
- N = sensors.size();
+ N = pids.size();
for (int i=0; i<N; i++) {
final HealthStatsWriter writer = new HealthStatsWriter(PidHealthStats.CONSTANTS);
writePid(writer, pids.valueAt(i));
@@ -241,7 +242,8 @@
addTimer(uidWriter, UidHealthStats.TIMER_CAMERA, uid.getCameraTurnedOnTimer());
// TIMER_FOREGROUND_ACTIVITY
- addTimer(uidWriter, UidHealthStats.TIMER_FOREGROUND_ACTIVITY, uid.getForegroundActivityTimer());
+ addTimer(uidWriter, UidHealthStats.TIMER_FOREGROUND_ACTIVITY,
+ uid.getForegroundActivityTimer());
// TIMER_BLUETOOTH_SCAN
addTimer(uidWriter, UidHealthStats.TIMER_BLUETOOTH_SCAN, uid.getBluetoothScanTimer());
diff --git a/services/core/java/com/android/server/connectivity/ApfFilter.java b/services/core/java/com/android/server/connectivity/ApfFilter.java
index 824db65..1ebd56c 100644
--- a/services/core/java/com/android/server/connectivity/ApfFilter.java
+++ b/services/core/java/com/android/server/connectivity/ApfFilter.java
@@ -509,8 +509,6 @@
mLastInstalledProgram = program;
if (VDBG) {
hexDump("Installing filter: ", program, program.length);
- } else {
- Log.d(TAG, "Installing filter length=" + program.length);
}
mConnectivityService.pushApfProgramToNetwork(mNai, program);
}
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/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 5b1cedc..fc412e3 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -20,6 +20,7 @@
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.app.Notification;
import android.app.NotificationManager;
@@ -66,9 +67,6 @@
private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
- private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
- private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
-
private static final int ROOT_UID = 0;
private final Context mContext;
@@ -101,7 +99,6 @@
mProfile = Preconditions.checkNotNull(profile);
final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
- configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true);
mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET);
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
index 2f55562..6f781b3 100644
--- a/services/core/java/com/android/server/net/NetworkStatsObservers.java
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -52,7 +52,7 @@
*/
class NetworkStatsObservers {
private static final String TAG = "NetworkStatsObservers";
- private static final boolean LOGV = true;
+ private static final boolean LOGV = false;
private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e66ec3c..fa0eb46 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4456,7 +4456,8 @@
}
}
- if ((permissionNames != null || dumpAll) && ps.pkg.requestedPermissions != null
+ if ((permissionNames != null || dumpAll) && ps.pkg != null
+ && ps.pkg.requestedPermissions != null
&& ps.pkg.requestedPermissions.size() > 0) {
final ArrayList<String> perms = ps.pkg.requestedPermissions;
pw.print(prefix); pw.println(" requested permissions:");
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index ad8acef0..0f251fd 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -62,8 +62,6 @@
private IInterface mBoundInterface;
private PendingEvent mPendingEvent;
-
-
private ManagedApplicationService(final Context context, final ComponentName component,
final int userId, int clientLabel, String settingsAction,
BinderChecker binderChecker) {
@@ -211,6 +209,7 @@
} else {
// Service connection wasn't pending, must have been disconnected
mContext.unbindService(this);
+ return;
}
try {
@@ -242,6 +241,8 @@
@Override
public void onServiceDisconnected(ComponentName componentName) {
Slog.w(TAG, "Service disconnected: " + intent);
+ mConnection = null;
+ mBoundInterface = null;
}
};
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 8316efa..93bb9d7 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -38,6 +38,17 @@
public abstract boolean isInVrMode();
/**
+ * Return {@code true} if the given package is the currently bound VrListenerService for the
+ * given user.
+ *
+ * @param packageName The package name to check.
+ * @param userId the user ID to check the package name for.
+ *
+ * @return {@code true} if the given package is the currently bound VrListenerService.
+ */
+ public abstract boolean isCurrentVrListener(String packageName, int userId);
+
+ /**
* Set the current VR mode state.
*
* @param enabled {@code true} to enable VR mode.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 6bf949c..aa6f59e 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -127,6 +127,11 @@
}
@Override
+ public boolean isCurrentVrListener(String packageName, int userId) {
+ return VrManagerService.this.isCurrentVrListener(packageName, userId);
+ }
+
+ @Override
public void registerListener(VrStateListener listener) {
VrManagerService.this.addListener(listener);
}
@@ -355,6 +360,16 @@
}
}
+ private boolean isCurrentVrListener(String packageName, int userId) {
+ synchronized (mLock) {
+ if (mCurrentVrService == null) {
+ return false;
+ }
+ return mCurrentVrService.getComponent().getPackageName().equals(packageName) &&
+ userId == mCurrentVrService.getUserId();
+ }
+ }
+
private void addListener(VrStateListener listener) {
synchronized (mLock) {
mListeners.add(listener);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 5cb7099..2a57d8e 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -43,9 +43,12 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
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;
@@ -943,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;
@@ -954,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);
@@ -964,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;
}
@@ -1015,6 +1037,7 @@
a = createAspectScaledThumbnailExitFreeformAnimationLocked(
containingFrame, surfaceInsets, taskId);
} else {
+ AnimationSet set = new AnimationSet(true);
mTmpFromClipRect.set(containingFrame);
mTmpToClipRect.set(containingFrame);
@@ -1025,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);
@@ -1467,6 +1502,12 @@
return a;
}
+ int getAppStackClipMode() {
+ return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
+ ? STACK_CLIP_NONE
+ : STACK_CLIP_AFTER_ANIM;
+ }
+
void postAnimationCallback() {
if (mNextAppTransitionCallback != null) {
mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 3a5dec9..6225fc6 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -23,6 +23,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import android.graphics.Matrix;
import android.util.Slog;
@@ -106,6 +107,7 @@
boolean usingTransferredAnimation = false;
private boolean mSkipFirstFrame = false;
+ private int mStackClip = STACK_CLIP_BEFORE_ANIM;
static final Animation sDummyAnimation = new DummyAnimation();
@@ -115,7 +117,8 @@
mAnimator = mService.mAnimator;
}
- public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame) {
+ public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame,
+ int stackClip) {
if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
+ ": " + anim + " wxh=" + width + "x" + height
+ " isVisible=" + mAppToken.isVisible());
@@ -142,6 +145,7 @@
transformation.clear();
transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
hasTransformation = true;
+ mStackClip = stackClip;
this.mSkipFirstFrame = skipFirstFrame;
@@ -186,6 +190,7 @@
mAppToken.allDrawn = false;
mAppToken.deferClearAllDrawn = false;
}
+ mStackClip = STACK_CLIP_BEFORE_ANIM;
}
public boolean isAnimating() {
@@ -201,6 +206,10 @@
deferThumbnailDestruction = false;
}
+ int getStackClip() {
+ return mStackClip;
+ }
+
void transferCurrentAnimation(
AppWindowAnimator toAppAnimator, WindowStateAnimator transferWinAnimator) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 36e8bbb..6741aba 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -96,6 +96,7 @@
private final Interpolator mMinimizedDockInterpolator;
private float mMaximizeMeetFraction;
private final Rect mTouchRegion = new Rect();
+ private boolean mAdjustingForIme;
DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -173,6 +174,14 @@
return mLastVisibility;
}
+ void setAdjustingForIme(boolean adjusting) {
+ mAdjustingForIme = adjusting;
+ }
+
+ boolean isAdjustingForIme() {
+ return mAdjustingForIme;
+ }
+
void positionDockedStackedDivider(Rect frame) {
TaskStack stack = mDisplayContent.getDockedStackLocked();
if (stack == null) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index c667767..8d67771 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -200,10 +200,11 @@
* @param bounds The adjusted bounds.
* @param keepInsets Whether to keep the insets from the original bounds or to calculate new
* ones depending on the adjusted bounds.
+ * @return true if the adjusted bounds has changed.
*/
- private void setAdjustedBounds(Rect bounds, boolean keepInsets) {
+ private boolean setAdjustedBounds(Rect bounds, boolean keepInsets) {
if (mAdjustedBounds.equals(bounds)) {
- return;
+ return false;
}
mAdjustedBounds.set(bounds);
@@ -211,6 +212,7 @@
alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
adjusted && keepInsets ? mBounds : null);
mDisplayContent.layoutNeeded = true;
+ return true;
}
private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
@@ -794,7 +796,9 @@
void setAdjustedForIme(WindowState imeWin) {
mAdjustedForIme = true;
mImeWin = imeWin;
- updateAdjustedBounds();
+ if (updateAdjustedBounds()) {
+ getDisplayContent().mDividerControllerLocked.setAdjustingForIme(true);
+ }
}
/**
@@ -803,7 +807,9 @@
void resetAdjustedForIme() {
mAdjustedForIme = false;
mImeWin = null;
- updateAdjustedBounds();
+ if (updateAdjustedBounds()) {
+ getDisplayContent().mDividerControllerLocked.setAdjustingForIme(true);
+ }
}
/**
@@ -920,7 +926,7 @@
/**
* Updates the adjustment depending on it's current state.
*/
- void updateAdjustedBounds() {
+ boolean updateAdjustedBounds() {
boolean adjust = false;
if (mMinimizeAmount != 0f) {
adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
@@ -931,7 +937,7 @@
mTmpAdjustedBounds.setEmpty();
mLastContentBounds.setEmpty();
}
- setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
+ return setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
}
boolean isAdjustedForMinimizedDockedStack() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index f243761..eae7838 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -36,6 +36,8 @@
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
@@ -406,7 +408,8 @@
Animation a = mPolicy.createForceHideEnterAnimation(false,
keyguardGoingAwayToShade);
- winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
+ winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime(),
+ STACK_CLIP_BEFORE_ANIM);
winAnimator.mKeyguardGoingAwayAnimation = true;
winAnimator.mKeyguardGoingAwayWithWallpaper
= keyguardGoingAwayWithWallpaper;
@@ -445,7 +448,7 @@
}
final AppWindowToken atoken = win.mAppToken;
- if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
+ if (winAnimator.mDrawState == READY_TO_SHOW) {
if (atoken == null || atoken.allDrawn) {
if (winAnimator.performShowLocked()) {
setPendingLayoutChanges(displayId,
@@ -487,7 +490,7 @@
if (a != null) {
if (DEBUG_KEYGUARD) Slog.v(TAG,
"Starting keyguard exit animation on window " + winAnimator.mWin);
- winAnimator.setAnimation(a);
+ winAnimator.setAnimation(a, STACK_CLIP_BEFORE_ANIM);
winAnimator.mKeyguardGoingAwayAnimation = true;
winAnimator.mKeyguardGoingAwayWithWallpaper
= keyguardGoingAwayWithWallpaper;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 14291ca..708ddff 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -236,6 +236,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -3039,7 +3040,7 @@
final int containingWidth = frame.width();
final int containingHeight = frame.height();
atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
- mAppTransition.canSkipFirstFrame());
+ mAppTransition.canSkipFirstFrame(), mAppTransition.getAppStackClipMode());
}
} else {
atoken.mAppAnimator.clearAnimation();
@@ -7352,6 +7353,30 @@
}
}
+ private void adjustForImeIfNeeded(final DisplayContent displayContent) {
+ final WindowState imeWin = mInputMethodWindow;
+ final TaskStack focusedStack =
+ mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
+ && isStackVisibleLocked(DOCKED_STACK_ID)
+ && focusedStack != null
+ && focusedStack.getDockSide() == DOCKED_BOTTOM){
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack.isVisibleLocked()) {
+ stack.setAdjustedForIme(imeWin);
+ }
+ }
+ } else {
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ stack.resetAdjustedForIme();
+ }
+ }
+ }
+
// -------------------------------------------------------------
// Drag and drop
// -------------------------------------------------------------
@@ -8209,30 +8234,8 @@
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
-
displayContent.getDockedDividerController().reevaluateVisibility(false);
-
- final WindowState imeWin = mInputMethodWindow;
- final TaskStack focusedStack =
- mCurrentFocus != null ? mCurrentFocus.getStack() : null;
- if (imeWin != null && imeWin.isVisibleNow()
- && isStackVisibleLocked(DOCKED_STACK_ID)
- && focusedStack != null
- && focusedStack.getDockSide() == DOCKED_BOTTOM){
- final ArrayList<TaskStack> stacks = displayContent.getStacks();
- for (int i = stacks.size() - 1; i >= 0; --i) {
- final TaskStack stack = stacks.get(i);
- if (stack.isVisibleLocked()) {
- stack.setAdjustedForIme(imeWin);
- }
- }
- } else {
- final ArrayList<TaskStack> stacks = displayContent.getStacks();
- for (int i = stacks.size() - 1; i >= 0; --i) {
- final TaskStack stack = stacks.get(i);
- stack.resetAdjustedForIme();
- }
- }
+ adjustForImeIfNeeded(displayContent);
}
}
break;
@@ -8971,7 +8974,7 @@
+ ", mDrawState=DRAW_PENDING in " + w
+ ", surfaceController " + winAnimator.mSurfaceController);
}
- winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+ winAnimator.mDrawState = DRAW_PENDING;
if (w.mAppToken != null) {
w.mAppToken.allDrawn = false;
w.mAppToken.deferClearAllDrawn = false;
@@ -10515,9 +10518,9 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
try {
- getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver);
+ getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
} catch (RemoteException e) {
}
}
@@ -10785,7 +10788,7 @@
final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
if (win.isVisibleLw()
&& (win.mAppToken != null || isForceHiding)) {
- win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+ win.mWinAnimator.mDrawState = DRAW_PENDING;
// Force add to mResizingWindows.
win.mLastContentInsets.set(-1, -1, -1, -1);
mWaitingForDrawn.add(win);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 04bd7fc..38fda1b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2528,7 +2528,7 @@
final int ph = mContainingFrame.height();
final Task task = getTask();
final boolean nonFullscreenTask = inMultiWindowMode();
- final boolean fitToDisplay = task != null && !task.isFloating();
+ final boolean fitToDisplay = task != null && !task.isFloating() && !layoutInParentFrame();
float x, y;
int w,h;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 22d3f98..83b6104 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -75,6 +75,25 @@
static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
+ /**
+ * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
+ * be applied after applying the animation transformation, i.e. the stack bounds don't move
+ * during the animation.
+ */
+ static final int STACK_CLIP_AFTER_ANIM = 0;
+
+ /**
+ * Mode how the window gets clipped by the stack bounds: The clipping should be applied before
+ * applying the animation transformation, i.e. the stack bounds move with the window.
+ */
+ static final int STACK_CLIP_BEFORE_ANIM = 1;
+
+ /**
+ * Mode how window gets clipped by the stack bounds during an animation: Don't clip the window
+ * by the stack bounds.
+ */
+ static final int STACK_CLIP_NONE = 2;
+
// Unchanging local convenience fields.
final WindowManagerService mService;
final WindowState mWin;
@@ -100,6 +119,7 @@
int mLastLayer;
long mAnimationStartTime;
long mLastAnimationTime;
+ int mStackClip = STACK_CLIP_BEFORE_ANIM;
/**
* Set when we have changed the size of the surface, to know that
@@ -128,7 +148,9 @@
boolean mHasClipRect;
Rect mClipRect = new Rect();
Rect mTmpClipRect = new Rect();
+ Rect mTmpFinalClipRect = new Rect();
Rect mLastClipRect = new Rect();
+ Rect mLastFinalClipRect = new Rect();
Rect mTmpStackBounds = new Rect();
/**
@@ -226,7 +248,7 @@
mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
}
- public void setAnimation(Animation anim, long startTime) {
+ public void setAnimation(Animation anim, long startTime, int stackClip) {
if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
mLocalAnimating = false;
@@ -238,10 +260,15 @@
mTransformation.setAlpha(mLastHidden ? 0 : 1);
mHasLocalTransformation = true;
mAnimationStartTime = startTime;
+ mStackClip = stackClip;
+ }
+
+ public void setAnimation(Animation anim, int stackClip) {
+ setAnimation(anim, -1, stackClip);
}
public void setAnimation(Animation anim) {
- setAnimation(anim, -1);
+ setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
}
public void clearAnimation() {
@@ -252,6 +279,7 @@
mAnimation = null;
mKeyguardGoingAwayAnimation = false;
mKeyguardGoingAwayWithWallpaper = false;
+ mStackClip = STACK_CLIP_BEFORE_ANIM;
}
}
@@ -397,6 +425,7 @@
if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
mHasTransformation = false;
mHasLocalTransformation = false;
+ mStackClip = STACK_CLIP_BEFORE_ANIM;
mWin.checkPolicyVisibilityChange();
mTransformation.clear();
if (mDrawState == HAS_DRAWN
@@ -1130,11 +1159,13 @@
}
}
- Rect calculateSurfaceWindowCrop() {
+ void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
final WindowState w = mWin;
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent == null) {
- return null;
+ clipRect.setEmpty();
+ finalClipRect.setEmpty();
+ return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
@@ -1170,7 +1201,6 @@
final boolean fullscreen = w.isFrameFullscreen(displayInfo);
final boolean isFreeformResizing =
w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
- final Rect clipRect = mTmpClipRect;
// We use the clip rect as provided by the tranformation for non-fullscreen windows to
// avoid premature clipping with the system decor rect.
@@ -1201,7 +1231,8 @@
// so we need to translate to match the actual surface coordinates.
clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
- adjustCropToStackBounds(w, clipRect, isFreeformResizing);
+ finalClipRect.setEmpty();
+ adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1210,35 +1241,39 @@
if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
clipRect.setEmpty();
}
-
- return clipRect;
}
- void updateSurfaceWindowCrop(Rect clipRect, boolean recoveringMemory) {
+ void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
}
+ if (!finalClipRect.equals(mLastFinalClipRect)) {
+ mLastFinalClipRect.set(finalClipRect);
+ mSurfaceController.setFinalCropInTransaction(finalClipRect);
+ }
}
- private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
+ private int resolveStackClip() {
+
+ // App animation overrides window animation stack clip mode.
+ if (mAppAnimator != null && mAppAnimator.animation != null) {
+ return mAppAnimator.getStackClip();
+ } else {
+ return mStackClip;
+ }
+ }
+ private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
+ boolean isFreeformResizing) {
final Task task = w.getTask();
if (task == null || !task.cropWindowsToStackBounds()) {
return;
}
- // We don't apply the stack bounds crop if:
- // 1. The window is currently animating in freeform mode, otherwise the animating window
- // will be suddenly (docked) or for whole animation (freeform) cut off.
- // 2. The window that is being replaced during animation, because it was living in a
- // different stack. If we suddenly crop it to the new stack bounds, it might get cut off.
- // We don't want it to happen, so we let it ignore the stack bounds until it gets removed.
- // The window that will replace it will abide them.
- // TODO: identify animations where we don't want to apply docked stack crop to the docked
- // task. For example, if the app is going from freeform to docked mode, we may not
- // want to apply the crop during the animation, since it will make the app appear
- // cropped prematurely.
- if (isAnimating() && (w.mWillReplaceWindow || w.inFreeformWorkspace())) {
+ final int stackClip = resolveStackClip();
+
+ // It's animating and we don't want to clip it to stack bounds during animation - abort.
+ if (isAnimating() && stackClip == STACK_CLIP_NONE) {
return;
}
@@ -1257,16 +1292,24 @@
final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+ // If we are animating, we either apply the clip before applying all the animation
+ // transformation or after all the transformation.
+ final boolean useFinalClipRect = isAnimating() && stackClip == STACK_CLIP_AFTER_ANIM;
+
// We need to do some acrobatics with surface position, because their clip region is
// relative to the inside of the surface, but the stack bounds aren't.
- clipRect.left = Math.max(0,
- Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
- clipRect.top = Math.max(0,
- Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
- clipRect.right = Math.max(0,
- Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
- clipRect.bottom = Math.max(0,
- Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
+ if (useFinalClipRect) {
+ finalClipRect.set(mTmpStackBounds);
+ } else {
+ clipRect.left = Math.max(0,
+ Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
+ clipRect.top = Math.max(0,
+ Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
+ clipRect.right = Math.max(0,
+ Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
+ clipRect.bottom = Math.max(0,
+ Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
+ }
}
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
@@ -1279,10 +1322,10 @@
float extraHScale = (float) 1.0;
float extraVScale = (float) 1.0;
- final Rect crop = calculateSurfaceWindowCrop();
+ calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
if (task != null && task.mStack.getForceScaleToCrop()) {
- extraHScale = crop.width() / (float)mTmpSize.width();
- extraVScale = crop.height() / (float)mTmpSize.height();
+ extraHScale = mTmpClipRect.width() / (float)mTmpSize.width();
+ extraVScale = mTmpClipRect.height() / (float)mTmpSize.height();
// In the case of ForceScaleToCrop we scale entire tasks together,
// and so we need to scale our offsets relative to the task bounds
@@ -1296,12 +1339,13 @@
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
// past where the system would have cropped us
- crop.set(0, 0, mTmpSize.width(), mTmpSize.height());
- updateSurfaceWindowCrop(crop, recoveringMemory);
+ mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
+ mTmpFinalClipRect.setEmpty();
+ updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
} else {
mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
recoveringMemory);
- updateSurfaceWindowCrop(crop, recoveringMemory);
+ updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
}
@@ -1458,7 +1502,8 @@
SurfaceControl.openTransaction();
mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
mWin.mFrame.top + top, false);
- updateSurfaceWindowCrop(calculateSurfaceWindowCrop(), false);
+ calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+ updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + left + "," + top + ")", e);
@@ -1721,6 +1766,7 @@
pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
pw.print(" mAnimation="); pw.println(mAnimation);
+ pw.print(" mStackClip="); pw.println(mStackClip);
}
if (mHasTransformation || mHasLocalTransformation) {
pw.print(prefix); pw.print("XForm: has=");
@@ -1740,6 +1786,9 @@
if (mHasClipRect) {
pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
}
+ if (!mLastFinalClipRect.isEmpty()) {
+ pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
+ }
pw.println();
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index be3ad3b..8799c61 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -189,6 +189,16 @@
}
}
+ void setFinalCropInTransaction(Rect clipRect) {
+ if (SHOW_TRANSACTIONS) logSurface(
+ "FINAL CROP " + clipRect.toShortString(), null);
+ try {
+ mSurfaceControl.setFinalCrop(clipRect);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error disconnecting surface in: " + this, e);
+ }
+ }
+
void setLayer(int layer) {
if (mSurfaceControl != null) {
SurfaceControl.openTransaction();
@@ -460,6 +470,7 @@
private final PointF mPosition = new PointF();
private final Point mSize = new Point();
private final Rect mWindowCrop = new Rect();
+ private final Rect mFinalCrop = new Rect();
private boolean mShown = false;
private int mLayerStack;
private boolean mIsOpaque;
@@ -545,6 +556,19 @@
}
@Override
+ public void setFinalCrop(Rect crop) {
+ if (crop != null) {
+ if (!crop.equals(mFinalCrop)) {
+ if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setFinalCrop("
+ + crop.toShortString() + "): OLD:" + this + ". Called by "
+ + Debug.getCallers(3));
+ mFinalCrop.set(crop);
+ }
+ }
+ super.setFinalCrop(crop);
+ }
+
+ @Override
public void setLayerStack(int layerStack) {
if (layerStack != mLayerStack) {
if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayerStack(" + layerStack + "): OLD:"
@@ -655,6 +679,7 @@
pw.print(" mSize="); pw.print(s.mSize.x); pw.print("x");
pw.println(s.mSize.y);
pw.print(" mCrop="); s.mWindowCrop.printShortString(pw); pw.println();
+ pw.print(" mFinalCrop="); s.mFinalCrop.printShortString(pw); pw.println();
pw.print(" Transform: ("); pw.print(s.mDsdx); pw.print(", ");
pw.print(s.mDtdx); pw.print(", "); pw.print(s.mDsdy);
pw.print(", "); pw.print(s.mDtdy); pw.println(")");
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 5ad771f..909c5f2 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -9,6 +9,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -689,6 +690,9 @@
&& !w.isDragResizing() && !adjustedForMinimizedDockedStack
&& (task == null || !w.getTask().mStack.getFreezeMovementAnimations())) {
winAnimator.setMoveAnimation(left, top);
+ } else if (w.mAttrs.type == TYPE_DOCK_DIVIDER &&
+ displayContent.getDockedDividerController().isAdjustingForIme()) {
+ winAnimator.setMoveAnimation(left, top);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -805,6 +809,8 @@
mService.updateResizingWindows(w);
}
+ displayContent.getDockedDividerController().setAdjustingForIme(false);
+
mService.mDisplayManagerInternal.setDisplayProperties(displayId,
mDisplayHasContent,
mPreferredRefreshRate,
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index e2562cd..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;
@@ -136,7 +138,7 @@
MessageUtils.findMessageNames(sMessageClasses);
// DHCP parameters that we request.
- private static final byte[] REQUESTED_PARAMS = new byte[] {
+ /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
DHCP_SUBNET_MASK,
DHCP_ROUTER,
DHCP_DNS_SERVER,
@@ -146,6 +148,7 @@
DHCP_LEASE_TIME,
DHCP_RENEWAL_TIME,
DHCP_REBINDING_TIME,
+ DHCP_VENDOR_INFO,
};
// DHCP flag that means "yes, we support unicast."
@@ -355,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");
@@ -456,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/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index c322ab8..876d95b 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -631,18 +631,10 @@
byte[] hwaddr = {
(byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
};
- byte[] params = new byte[] {
- DHCP_SUBNET_MASK,
- DHCP_ROUTER,
- DHCP_DNS_SERVER,
- DHCP_DOMAIN_NAME,
- DHCP_MTU,
- DHCP_LEASE_TIME,
- };
ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
- false /* do unicast */, params);
+ false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
byte[] headers = new byte[] {
// Ethernet header.
@@ -650,14 +642,14 @@
(byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
(byte) 0x08, (byte) 0x00,
// IP header.
- (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x52,
+ (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
(byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
- (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x8c,
+ (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// UDP header.
(byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
- (byte) 0x01, (byte) 0x3e, (byte) 0xd8, (byte) 0xa4,
+ (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
// BOOTP.
(byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
@@ -688,13 +680,17 @@
'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
// Requested parameter list.
- (byte) 0x37, (byte) 0x06,
+ (byte) 0x37, (byte) 0x0a,
DHCP_SUBNET_MASK,
DHCP_ROUTER,
DHCP_DNS_SERVER,
DHCP_DOMAIN_NAME,
DHCP_MTU,
+ DHCP_BROADCAST_ADDRESS,
DHCP_LEASE_TIME,
+ DHCP_RENEWAL_TIME,
+ DHCP_REBINDING_TIME,
+ DHCP_VENDOR_INFO,
// End options.
(byte) 0xff,
// Our packets are always of even length. TODO: find out why and possibly fix it.
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/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index a848346..75e837b 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -9,17 +9,37 @@
from fontTools import ttLib
LANG_TO_SCRIPT = {
+ 'as': 'Beng',
+ 'bn': 'Beng',
+ 'cy': 'Latn',
+ 'da': 'Latn',
'de': 'Latn',
'en': 'Latn',
'es': 'Latn',
+ 'et': 'Latn',
'eu': 'Latn',
- 'ja': 'Jpan',
- 'ko': 'Kore',
+ 'fr': 'Latn',
+ 'ga': 'Latn',
+ 'gu': 'Gujr',
+ 'hi': 'Deva',
+ 'hr': 'Latn',
'hu': 'Latn',
'hy': 'Armn',
+ 'ja': 'Jpan',
+ 'kn': 'Knda',
+ 'ko': 'Kore',
+ 'ml': 'Mlym',
+ 'mn': 'Cyrl',
+ 'mr': 'Deva',
'nb': 'Latn',
'nn': 'Latn',
+ 'or': 'Orya',
+ 'pa': 'Guru',
'pt': 'Latn',
+ 'sl': 'Latn',
+ 'ta': 'Taml',
+ 'te': 'Telu',
+ 'tk': 'Latn',
}
def lang_to_script(lang_code):
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
index 985dd5a..6c775b9 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -21,6 +21,7 @@
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.LayoutlibCallback;
+import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
@@ -84,7 +85,7 @@
return new BridgeTypedArray(resources, resources.mContext, numEntries, platformFile);
}
- private static Pair<String, ResourceValue> getResourceValue(Resources resources, int id,
+ private static Pair<ResourceType, String> getResourceInfo(Resources resources, int id,
boolean[] platformResFlag_out) {
// first get the String related to this id in the framework
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
@@ -97,11 +98,7 @@
if (resourceInfo != null) {
platformResFlag_out[0] = true;
- String attributeName = resourceInfo.getSecond();
-
- return Pair.of(attributeName,
- resources.mContext.getRenderResources().getFrameworkResource(
- resourceInfo.getFirst(), attributeName));
+ return resourceInfo;
}
// didn't find a match in the framework? look in the project.
@@ -110,13 +107,24 @@
if (resourceInfo != null) {
platformResFlag_out[0] = false;
- String attributeName = resourceInfo.getSecond();
-
- return Pair.of(attributeName,
- resources.mContext.getRenderResources().getProjectResource(
- resourceInfo.getFirst(), attributeName));
+ return resourceInfo;
}
}
+ return null;
+ }
+
+ private static Pair<String, ResourceValue> getResourceValue(Resources resources, int id,
+ boolean[] platformResFlag_out) {
+ Pair<ResourceType, String> resourceInfo =
+ getResourceInfo(resources, id, platformResFlag_out);
+
+ if (resourceInfo != null) {
+ String attributeName = resourceInfo.getSecond();
+ RenderResources renderResources = resources.mContext.getRenderResources();
+ return Pair.of(attributeName, platformResFlag_out[0] ?
+ renderResources.getFrameworkResource(resourceInfo.getFirst(), attributeName) :
+ renderResources.getProjectResource(resourceInfo.getFirst(), attributeName));
+ }
return null;
}
@@ -626,17 +634,57 @@
@LayoutlibDelegate
static String getResourceEntryName(Resources resources, int resid) throws NotFoundException {
- throw new UnsupportedOperationException();
+ Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, new boolean[1]);
+ if (resourceInfo != null) {
+ return resourceInfo.getSecond();
+ }
+ throwException(resid, null);
+ return null;
+
}
@LayoutlibDelegate
static String getResourceName(Resources resources, int resid) throws NotFoundException {
- throw new UnsupportedOperationException();
+ boolean[] platformOut = new boolean[1];
+ Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
+ String namespace;
+ if (resourceInfo != null) {
+ if (platformOut[0]) {
+ namespace = SdkConstants.ANDROID_NS_NAME;
+ } else {
+ namespace = resources.mContext.getPackageName();
+ namespace = namespace == null ? SdkConstants.APP_PREFIX : namespace;
+ }
+ return namespace + ':' + resourceInfo.getFirst().getName() + '/' +
+ resourceInfo.getSecond();
+ }
+ throwException(resid, null);
+ return null;
+ }
+
+ @LayoutlibDelegate
+ static String getResourcePackageName(Resources resources, int resid) throws NotFoundException {
+ boolean[] platformOut = new boolean[1];
+ Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
+ if (resourceInfo != null) {
+ if (platformOut[0]) {
+ return SdkConstants.ANDROID_NS_NAME;
+ }
+ String packageName = resources.mContext.getPackageName();
+ return packageName == null ? SdkConstants.APP_PREFIX : packageName;
+ }
+ throwException(resid, null);
+ return null;
}
@LayoutlibDelegate
static String getResourceTypeName(Resources resources, int resid) throws NotFoundException {
- throw new UnsupportedOperationException();
+ Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, new boolean[1]);
+ if (resourceInfo != null) {
+ return resourceInfo.getFirst().getName();
+ }
+ throwException(resid, null);
+ return null;
}
@LayoutlibDelegate
@@ -849,22 +897,17 @@
* @throws NotFoundException
*/
private static void throwException(Resources resources, int id) throws NotFoundException {
- // first get the String related to this id in the framework
- Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
+ throwException(id, getResourceInfo(resources, id, new boolean[1]));
+ }
- // if the name is unknown in the framework, get it from the custom view loader.
- if (resourceInfo == null && resources.mLayoutlibCallback != null) {
- resourceInfo = resources.mLayoutlibCallback.resolveResourceId(id);
- }
-
+ private static void throwException(int id, @Nullable Pair<ResourceType, String> resourceInfo) {
String message;
if (resourceInfo != null) {
message = String.format(
"Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
resourceInfo.getFirst(), id, resourceInfo.getSecond());
} else {
- message = String.format(
- "Could not resolve resource value: 0x%1$X.", id);
+ message = String.format("Could not resolve resource value: 0x%1$X.", id);
}
throw new NotFoundException(message);
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 7f41348..309c1b8 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -564,7 +564,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ public void requestAppKeyboardShortcuts(
+ IResultReceiver receiver, int deviceId) throws RemoteException {
}
@Override
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 411417c..1ea8a9f 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -141,9 +141,4 @@
public void onActionModeFinished(ActionMode mode) {
}
-
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu) {
-
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 533a10a..a83f100 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -103,7 +103,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ public void requestAppKeyboardShortcuts(
+ IResultReceiver receiver, int deviceId) throws RemoteException {
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index d417eb7..3031701 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -66,6 +66,6 @@
@Override
public void requestAppKeyboardShortcuts(
- KeyboardShortcutsReceiver receiver) {
+ KeyboardShortcutsReceiver receiver, int deviceId) {
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
index 08a8faf..161bf41 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
@@ -27,8 +27,8 @@
public class DynamicIdMap {
- private final Map<Pair<ResourceType, String>, Integer> mDynamicIds = new HashMap<Pair<ResourceType, String>, Integer>();
- private final SparseArray<Pair<ResourceType, String>> mRevDynamicIds = new SparseArray<Pair<ResourceType, String>>();
+ private final Map<Pair<ResourceType, String>, Integer> mDynamicIds = new HashMap<>();
+ private final SparseArray<Pair<ResourceType, String>> mRevDynamicIds = new SparseArray<>();
private int mDynamicSeed;
public DynamicIdMap(int seed) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f32bb76..1a00cc9 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -168,6 +168,7 @@
"android.content.res.Resources#getLayout",
"android.content.res.Resources#getResourceEntryName",
"android.content.res.Resources#getResourceName",
+ "android.content.res.Resources#getResourcePackageName",
"android.content.res.Resources#getResourceTypeName",
"android.content.res.Resources#getString",
"android.content.res.Resources#getStringArray",
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index a9259fa..67cf107 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,11 @@
*/
public int anqpDomainId;
+ /*
+ * This field is equivalent to the |flags|, rather than the |capabilities| field
+ * of the per-BSS scan results returned by WPA supplicant. See the definition of
+ * |struct wpa_bss| in wpa_supplicant/bss.h for more details.
+ */
/**
* Describes the authentication, key management, and encryption schemes
* supported by the access point.
@@ -211,6 +216,10 @@
/** {@hide} */
public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002;
+ /*
+ * These flags are specific to the ScanResult class, and are not related to the |flags|
+ * field of the per-BSS scan results from WPA supplicant.
+ */
/**
* Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
* {@hide}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7dc8049..06dea07 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -684,6 +684,13 @@
/**
* @hide
+ * A hint about whether or not the network represented by this WifiConfiguration
+ * is metered.
+ */
+ public boolean meteredHint;
+
+ /**
+ * @hide
* Number of time the scorer overrode a the priority based choice, when comparing two
* WifiConfigurations, note that since comparing WifiConfiguration happens very often
* potentially at every scan, this number might become very large, even on an idle
@@ -1302,6 +1309,7 @@
selfAdded = false;
didSelfAdd = false;
ephemeral = false;
+ meteredHint = false;
validatedInternetAccess = false;
mIpConfiguration = new IpConfiguration();
lastUpdateUid = -1;
@@ -1399,7 +1407,9 @@
if (this.selfAdded) sbuf.append(" selfAdded");
if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
- if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess || this.ephemeral) {
+ if (this.meteredHint) sbuf.append(" meteredHint");
+ if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
+ || this.ephemeral || this.meteredHint) {
sbuf.append("\n");
}
sbuf.append(" KeyMgmt:");
@@ -1546,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 "";
@@ -1832,6 +1830,7 @@
selfAdded = source.selfAdded;
validatedInternetAccess = source.validatedInternetAccess;
ephemeral = source.ephemeral;
+ meteredHint = source.meteredHint;
if (source.visibility != null) {
visibility = new Visibility(source.visibility);
}
@@ -1870,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) {
@@ -1916,6 +1910,7 @@
dest.writeInt(didSelfAdd ? 1 : 0);
dest.writeInt(validatedInternetAccess ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
+ dest.writeInt(meteredHint ? 1 : 0);
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
dest.writeInt(lastUpdateUid);
@@ -1985,6 +1980,7 @@
config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
+ config.meteredHint = in.readInt() != 0;
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
config.lastUpdateUid = in.readInt();