Merge "Allow override of Motoya with full NotoSans"
diff --git a/api/current.txt b/api/current.txt
index 904d9a99..e649b4d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -92,6 +92,7 @@
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
field public static final java.lang.String NFC = "android.permission.NFC";
+ field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
@@ -1360,6 +1361,7 @@
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
field public static final int userVisible = 16843409; // 0x1010291
+ field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
field public static final int value = 16842788; // 0x1010024
field public static final int valueFrom = 16843486; // 0x10102de
field public static final int valueTo = 16843487; // 0x10102df
@@ -5720,6 +5722,7 @@
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+ field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
@@ -5905,6 +5908,37 @@
field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
}
+ public class NetworkStatsManager {
+ method public android.app.usage.NetworkUsageStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ }
+
+ public final class NetworkUsageStats implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean getNextBucket(android.app.usage.NetworkUsageStats.Bucket);
+ method public boolean hasNextBucket();
+ }
+
+ public static class NetworkUsageStats.Bucket {
+ ctor public NetworkUsageStats.Bucket();
+ method public long getEndTimeStamp();
+ method public long getRxBytes();
+ method public long getRxPackets();
+ method public long getStartTimeStamp();
+ method public int getState();
+ method public long getTxBytes();
+ method public long getTxPackets();
+ method public int getUid();
+ field public static final int STATE_ALL = -1; // 0xffffffff
+ field public static final int STATE_DEFAULT = 1; // 0x1
+ field public static final int STATE_FOREGROUND = 2; // 0x2
+ field public static final int UID_REMOVED = -4; // 0xfffffffc
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -6954,6 +6988,7 @@
field public static final int SCAN_MODE_BALANCED = 1; // 0x1
field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+ field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
}
public static final class ScanSettings.Builder {
@@ -7562,6 +7597,7 @@
field public static final int MODE_PRIVATE = 0; // 0x0
field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
+ field public static final java.lang.String NETWORK_STATS_SERVICE = "netstats";
field public static final java.lang.String NFC_SERVICE = "nfc";
field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
@@ -8693,6 +8729,7 @@
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
+ field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
field public java.lang.String backupAgentName;
field public java.lang.String className;
@@ -14575,6 +14612,14 @@
field public static final int SUCCESS = 0; // 0x0
}
+ public static class AudioRecord.Builder {
+ ctor public AudioRecord.Builder();
+ method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
+ method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
+ }
+
public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioRecord);
method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -15196,6 +15241,7 @@
method public android.graphics.Bitmap getIconBitmap();
method public android.net.Uri getIconUri();
method public java.lang.String getMediaId();
+ method public android.net.Uri getMediaUri();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
@@ -15210,6 +15256,7 @@
method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
+ method public android.media.MediaDescription.Builder setMediaUri(android.net.Uri);
method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
}
@@ -17027,6 +17074,7 @@
method public void play();
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
+ method public void playFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -17074,6 +17122,7 @@
method public void onPlay();
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -17128,6 +17177,7 @@
field public static final long ACTION_PLAY = 4L; // 0x4L
field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
@@ -18583,7 +18633,10 @@
field public int frequency;
field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -18610,6 +18663,7 @@
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -26702,6 +26756,16 @@
method public void copy1DRangeFromUnchecked(int, int, short[]);
method public void copy1DRangeFromUnchecked(int, int, byte[]);
method public void copy1DRangeFromUnchecked(int, int, float[]);
+ method public void copy1DRangeTo(int, int, java.lang.Object);
+ method public void copy1DRangeTo(int, int, int[]);
+ method public void copy1DRangeTo(int, int, short[]);
+ method public void copy1DRangeTo(int, int, byte[]);
+ method public void copy1DRangeTo(int, int, float[]);
+ method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeToUnchecked(int, int, int[]);
+ method public void copy1DRangeToUnchecked(int, int, short[]);
+ method public void copy1DRangeToUnchecked(int, int, byte[]);
+ method public void copy1DRangeToUnchecked(int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
method public void copy2DRangeFrom(int, int, int, int, byte[]);
method public void copy2DRangeFrom(int, int, int, int, short[]);
@@ -26709,6 +26773,14 @@
method public void copy2DRangeFrom(int, int, int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int);
method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
+ method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeTo(int, int, int, int, byte[]);
+ method public void copy2DRangeTo(int, int, int, int, short[]);
+ method public void copy2DRangeTo(int, int, int, int, int[]);
+ method public void copy2DRangeTo(int, int, int, int, float[]);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int);
+ method public void copy3DRangeTo(int, int, int, int, int, int, java.lang.Object);
method public void copyFrom(android.renderscript.BaseObj[]);
method public void copyFrom(java.lang.Object);
method public void copyFrom(int[]);
@@ -26728,6 +26800,7 @@
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public void copyToFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -26753,6 +26826,7 @@
method public deprecated synchronized void resize(int);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
+ method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener);
method public void setSurface(android.view.Surface);
method public void syncAll(int);
@@ -27698,6 +27772,11 @@
method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
}
+ public class NetworkSecurityPolicy {
+ method public static android.security.NetworkSecurityPolicy getInstance();
+ method public boolean isCleartextTrafficPermitted();
+ }
+
}
package android.service.carrier {
@@ -36153,6 +36232,7 @@
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
}
public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/api/system-current.txt b/api/system-current.txt
index 09114fe..402cf05 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1436,6 +1436,7 @@
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
field public static final int userVisible = 16843409; // 0x1010291
+ field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
field public static final int value = 16842788; // 0x1010024
field public static final int valueFrom = 16843486; // 0x10102de
field public static final int valueTo = 16843487; // 0x10102df
@@ -5824,6 +5825,7 @@
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+ field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
@@ -6085,6 +6087,37 @@
field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
}
+ public class NetworkStatsManager {
+ method public android.app.usage.NetworkUsageStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ }
+
+ public final class NetworkUsageStats implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean getNextBucket(android.app.usage.NetworkUsageStats.Bucket);
+ method public boolean hasNextBucket();
+ }
+
+ public static class NetworkUsageStats.Bucket {
+ ctor public NetworkUsageStats.Bucket();
+ method public long getEndTimeStamp();
+ method public long getRxBytes();
+ method public long getRxPackets();
+ method public long getStartTimeStamp();
+ method public int getState();
+ method public long getTxBytes();
+ method public long getTxPackets();
+ method public int getUid();
+ field public static final int STATE_ALL = -1; // 0xffffffff
+ field public static final int STATE_DEFAULT = 1; // 0x1
+ field public static final int STATE_FOREGROUND = 2; // 0x2
+ field public static final int UID_REMOVED = -4; // 0xfffffffc
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -7149,6 +7182,7 @@
field public static final int SCAN_MODE_BALANCED = 1; // 0x1
field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+ field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
}
@@ -7771,6 +7805,7 @@
field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score";
+ field public static final java.lang.String NETWORK_STATS_SERVICE = "netstats";
field public static final java.lang.String NFC_SERVICE = "nfc";
field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
@@ -8912,6 +8947,7 @@
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
+ field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
field public java.lang.String backupAgentName;
field public java.lang.String className;
@@ -15774,6 +15810,16 @@
field public static final int SUCCESS = 0; // 0x0
}
+ public static class AudioRecord.Builder {
+ ctor public AudioRecord.Builder();
+ method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
+ method public android.media.AudioRecord.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
+ }
+
public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioRecord);
method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -16395,6 +16441,7 @@
method public android.graphics.Bitmap getIconBitmap();
method public android.net.Uri getIconUri();
method public java.lang.String getMediaId();
+ method public android.net.Uri getMediaUri();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
@@ -16409,6 +16456,7 @@
method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
+ method public android.media.MediaDescription.Builder setMediaUri(android.net.Uri);
method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
}
@@ -18293,6 +18341,7 @@
method public void play();
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
+ method public void playFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -18340,6 +18389,7 @@
method public void onPlay();
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -18394,6 +18444,7 @@
field public static final long ACTION_PLAY = 4L; // 0x4L
field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
@@ -20079,7 +20130,8 @@
}
public class RttManager {
- method public android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
method public void stopRanging(android.net.wifi.RttManager.RttListener);
field public static final int BASE = 160256; // 0x27200
@@ -20089,10 +20141,19 @@
field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
field public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
field public static final java.lang.String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ field public static final int PREAMBLE_HT = 2; // 0x2
+ field public static final int PREAMBLE_LEGACY = 1; // 0x1
+ field public static final int PREAMBLE_VHT = 4; // 0x4
field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+ field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+ field public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+ field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+ field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+ field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
field public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
field public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
field public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
@@ -20100,26 +20161,31 @@
field public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
field public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
field public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
- field public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+ field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
field public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
field public static final int RTT_STATUS_ABORTED = 8; // 0x8
field public static final int RTT_STATUS_FAILURE = 1; // 0x1
field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+ field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+ field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
field public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+ field public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+ field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
- field public static final int RTT_TYPE_11_MC = 4; // 0x4
- field public static final int RTT_TYPE_11_V = 2; // 0x2
+ field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
- field public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+ field public static final int RTT_TYPE_TWO_SIDED = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
}
- public class RttManager.Capabilities {
+ public deprecated class RttManager.Capabilities {
ctor public RttManager.Capabilities();
field public int supportedPeerType;
field public int supportedType;
@@ -20138,6 +20204,20 @@
field public android.net.wifi.RttManager.RttResult[] mResults;
}
+ public static class RttManager.RttCapabilities implements android.os.Parcelable {
+ ctor public RttManager.RttCapabilities();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public int bwSupported;
+ field public boolean lciSupported;
+ field public boolean lcrSupported;
+ field public boolean oneSidedRttSupported;
+ field public int preambleSupported;
+ field public deprecated boolean supportedPeerType;
+ field public deprecated boolean supportedType;
+ field public boolean twoSided11McRttSupported;
+ }
+
public static abstract interface RttManager.RttListener {
method public abstract void onAborted();
method public abstract void onFailure(int, java.lang.String);
@@ -20146,30 +20226,64 @@
public static class RttManager.RttParams {
ctor public RttManager.RttParams();
+ field public boolean LCIRequest;
+ field public boolean LCRRequest;
+ field public int bandwidth;
field public java.lang.String bssid;
+ field public int burstTimeout;
+ field public int centerFreq0;
+ field public int centerFreq1;
field public int channelWidth;
field public int deviceType;
field public int frequency;
- field public int num_retries;
- field public int num_samples;
+ field public int interval;
+ field public int numRetriesPerFTMR;
+ field public int numRetriesPerMeasurementFrame;
+ field public int numSamplesPerBurst;
+ field public deprecated int num_retries;
+ field public deprecated int num_samples;
+ field public int numberBurst;
+ field public int preamble;
field public int requestType;
}
public static class RttManager.RttResult {
ctor public RttManager.RttResult();
field public java.lang.String bssid;
- field public int distance_cm;
- field public int distance_sd_cm;
- field public int distance_spread_cm;
- field public int requestType;
+ field public int burstDuration;
+ field public int burstNumber;
+ field public int distance;
+ field public int distanceSpread;
+ field public int distanceStandardDeviation;
+ field public deprecated int distance_cm;
+ field public deprecated int distance_sd_cm;
+ field public deprecated int distance_spread_cm;
+ field public int frameNumberPerBurstPeer;
+ field public int measurementFrameNumber;
+ field public int measurementType;
+ field public deprecated int requestType;
+ field public int retryAfterDuration;
field public int rssi;
- field public int rssi_spread;
- field public long rtt_ns;
- field public long rtt_sd_ns;
- field public long rtt_spread_ns;
+ field public int rssiSpread;
+ field public deprecated int rssi_spread;
+ field public long rtt;
+ field public long rttSpread;
+ field public long rttStandardDeviation;
+ field public deprecated long rtt_ns;
+ field public deprecated long rtt_sd_ns;
+ field public deprecated long rtt_spread_ns;
+ field public int rxRate;
field public int status;
+ field public int successMeasurementFrameNumber;
field public long ts;
- field public int tx_rate;
+ field public int txRate;
+ field public deprecated int tx_rate;
+ }
+
+ public class RttManager.wifiInformationElement {
+ ctor public RttManager.wifiInformationElement();
+ field public java.lang.String data;
+ field public int id;
}
public class ScanResult implements android.os.Parcelable {
@@ -20189,7 +20303,10 @@
field public int frequency;
field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -20216,6 +20333,7 @@
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -24686,6 +24804,7 @@
method public boolean isDeviceIdleMode();
method public boolean isInteractive();
method public boolean isPowerSaveMode();
+ method public boolean isScreenBrightnessBoosted();
method public deprecated boolean isScreenOn();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
@@ -24694,6 +24813,7 @@
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
+ field public static final java.lang.String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
@@ -28509,6 +28629,16 @@
method public void copy1DRangeFromUnchecked(int, int, short[]);
method public void copy1DRangeFromUnchecked(int, int, byte[]);
method public void copy1DRangeFromUnchecked(int, int, float[]);
+ method public void copy1DRangeTo(int, int, java.lang.Object);
+ method public void copy1DRangeTo(int, int, int[]);
+ method public void copy1DRangeTo(int, int, short[]);
+ method public void copy1DRangeTo(int, int, byte[]);
+ method public void copy1DRangeTo(int, int, float[]);
+ method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeToUnchecked(int, int, int[]);
+ method public void copy1DRangeToUnchecked(int, int, short[]);
+ method public void copy1DRangeToUnchecked(int, int, byte[]);
+ method public void copy1DRangeToUnchecked(int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
method public void copy2DRangeFrom(int, int, int, int, byte[]);
method public void copy2DRangeFrom(int, int, int, int, short[]);
@@ -28516,6 +28646,14 @@
method public void copy2DRangeFrom(int, int, int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int);
method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
+ method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeTo(int, int, int, int, byte[]);
+ method public void copy2DRangeTo(int, int, int, int, short[]);
+ method public void copy2DRangeTo(int, int, int, int, int[]);
+ method public void copy2DRangeTo(int, int, int, int, float[]);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int);
+ method public void copy3DRangeTo(int, int, int, int, int, int, java.lang.Object);
method public void copyFrom(android.renderscript.BaseObj[]);
method public void copyFrom(java.lang.Object);
method public void copyFrom(int[]);
@@ -28535,6 +28673,7 @@
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public void copyToFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -28560,6 +28699,7 @@
method public deprecated synchronized void resize(int);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
+ method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener);
method public void setSurface(android.view.Surface);
method public void syncAll(int);
@@ -29505,6 +29645,11 @@
method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
}
+ public class NetworkSecurityPolicy {
+ method public static android.security.NetworkSecurityPolicy getInstance();
+ method public boolean isCleartextTrafficPermitted();
+ }
+
}
package android.service.carrier {
@@ -38526,6 +38671,7 @@
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
}
public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 29ba1d7..0a53371 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -112,7 +112,7 @@
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--user <USER_ID> | current]\n" +
" [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" +
- " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
+ " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" +
" am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
" am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
" am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
@@ -1031,6 +1031,7 @@
boolean wall = false;
int userId = UserHandle.USER_CURRENT;
int profileType = 0;
+ mSamplingInterval = 0;
String process = null;
@@ -1044,6 +1045,8 @@
userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--wall")) {
wall = true;
+ } else if (opt.equals("--sampling")) {
+ mSamplingInterval = Integer.parseInt(nextArgRequired());
} else {
System.err.println("Error: Unknown option: " + opt);
return;
@@ -1093,7 +1096,7 @@
System.err.println("Consider using a file under /data/local/tmp/");
return;
}
- profilerInfo = new ProfilerInfo(profileFile, fd, 0, false);
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
}
try {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fd7bae7..59fe490 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -27,6 +27,7 @@
import android.app.job.JobScheduler;
import android.app.trust.TrustManager;
import android.app.usage.IUsageStatsManager;
+import android.app.usage.NetworkStatsManager;
import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
@@ -639,6 +640,13 @@
return new UsageStatsManager(ctx.getOuterContext(), service);
}});
+ registerService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class,
+ new CachedServiceFetcher<NetworkStatsManager>() {
+ @Override
+ public NetworkStatsManager createService(ContextImpl ctx) {
+ return new NetworkStatsManager(ctx.getOuterContext());
+ }});
+
registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
new StaticServiceFetcher<JobScheduler>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8c81133..cf6619f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,7 +20,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.Activity;
-import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -176,7 +175,8 @@
*
* <p>This component is set as device owner and active admin when device owner provisioning is
* started by an NFC message containing an NFC record with MIME type
- * {@link #MIME_TYPE_PROVISIONING_NFC}.
+ * {@link #MIME_TYPE_PROVISIONING_NFC_V2}. For the NFC record, the component name should be
+ * flattened to a string, via {@link ComponentName#flattenToShortString()}.
*
* @see DeviceAdminReceiver
*/
@@ -346,7 +346,7 @@
* {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION} if the version of the
* installed package is less than this version code.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE
@@ -392,21 +392,23 @@
* A boolean extra indicating whether device encryption is required as part of Device Owner
* provisioning.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
/**
- * On devices managed by a device owner app, a String representation of a Component name extra
- * indicating the component of the application that is temporarily granted device owner
- * privileges during device initialization and profile owner privileges during secondary user
- * initialization.
+ * On devices managed by a device owner app, a {@link ComponentName} extra indicating the
+ * component of the application that is temporarily granted device owner privileges during
+ * device initialization and profile owner privileges during secondary user initialization.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
- * provisioning via an NFC bump.
- * @see ComponentName#unflattenFromString()
+ * <p>
+ * It can also be used in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts
+ * device owner provisioning via an NFC bump. For the NFC record, it should be flattened to a
+ * string first.
+ *
+ * @see ComponentName#flattenToShortString()
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
@@ -416,7 +418,7 @@
* initializer package. When not provided it is assumed that the device initializer package is
* already installed.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
@@ -428,7 +430,7 @@
* {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION} if the version of
* the installed package is less than this version code.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE
@@ -438,7 +440,7 @@
* A String extra holding a http cookie header which should be used in the http request to the
* url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
@@ -451,7 +453,7 @@
* match the file at the download location an error will be shown to the user and the user will
* be asked to factory reset the device.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
@@ -461,7 +463,7 @@
* A String extra holding the MAC address of the Bluetooth device to connect to with status
* updates during provisioning.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS
@@ -473,7 +475,7 @@
*
* <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_BT_UUID
@@ -485,7 +487,7 @@
*
* <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_BT_DEVICE_ID
@@ -495,31 +497,26 @@
* A Boolean extra that that will cause a provisioned device to temporarily proxy network
* traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_BT_USE_PROXY
= "android.app.extra.PROVISIONING_BT_USE_PROXY";
-
/**
- * This MIME type is used for starting the Device Owner provisioning.
+ * This MIME type is used for starting the Device Owner provisioning that does not require
+ * provisioning features introduced in Android API level
+ * {@link android.os.Build.VERSION_CODES#MNC} or later levels.
*
- * <p>During device owner provisioning a device admin app is set as the owner of the device.
- * A device owner has full control over the device. The device owner can not be modified by the
- * user and the only way of resetting the device is if the device owner app calls a factory
- * reset.
- *
- * <p> A typical use case would be a device that is owned by a company, but used by either an
- * employee or client.
- *
- * <p> The NFC message should be send to an unprovisioned device.
+ * <p>For more information about the provisioning process see
+ * {@link #MIME_TYPE_PROVISIONING_NFC_V2}.
*
* <p>The NFC record must contain a serialized {@link java.util.Properties} object which
* contains the following properties:
* <ul>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li>
* <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCALE}, optional</li>
@@ -530,17 +527,56 @@
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li></ul>
*
* <p>
- * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
- * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although
- * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
- * This componentName must have been converted to a String via
- * {@link android.content.ComponentName#flattenToString()}
+ * As of {@link android.os.Build.VERSION_CODES#MNC}, the properties should contain
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead of
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}, (although specifying only
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
+ *
+ * @see #MIME_TYPE_PROVISIONING_NFC_V2
+ *
+ */
+ public static final String MIME_TYPE_PROVISIONING_NFC
+ = "application/com.android.managedprovisioning";
+
+
+ /**
+ * This MIME type is used for starting the Device Owner provisioning that requires
+ * new provisioning features introduced in API version
+ * {@link android.os.Build.VERSION_CODES#MNC} in addition to those supported in earlier
+ * versions.
+ *
+ * <p>During device owner provisioning a device admin app is set as the owner of the device.
+ * A device owner has full control over the device. The device owner can not be modified by the
+ * user and the only way of resetting the device is if the device owner app calls a factory
+ * reset.
+ *
+ * <p> A typical use case would be a device that is owned by a company, but used by either an
+ * employee or client.
+ *
+ * <p> The NFC message should be sent to an unprovisioned device.
+ *
+ * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
+ * contains the following properties in addition to properties listed at
+ * {@link #MIME_TYPE_PROVISIONING_NFC}:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.
+ * Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property
+ * should be converted to a String via
+ * {@link android.content.ComponentName#flattenToString()}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul>
*
* <p> When device owner provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -552,8 +588,8 @@
* <p>Input: Nothing.</p>
* <p>Output: Nothing</p>
*/
- public static final String MIME_TYPE_PROVISIONING_NFC
- = "application/com.android.managedprovisioning";
+ public static final String MIME_TYPE_PROVISIONING_NFC_V2
+ = "application/com.android.managedprovisioning.v2";
/**
* Activity action: ask the user to add a new device administrator to the system.
@@ -578,11 +614,10 @@
/**
* @hide
* Activity action: ask the user to add a new device administrator as the profile owner
- * for this user. Only system privileged apps that have MANAGE_USERS and MANAGE_DEVICE_ADMINS
- * permission can call this API.
+ * for this user. Only system apps can launch this intent.
*
- * <p>The ComponentName of the profile owner admin is pass in {@link #EXTRA_DEVICE_ADMIN} extra
- * field. This will invoke a UI to bring the user through adding the profile owner admin
+ * <p>The ComponentName of the profile owner admin is passed in the {@link #EXTRA_DEVICE_ADMIN}
+ * extra field. This will invoke a UI to bring the user through adding the profile owner admin
* to remotely control restrictions on the user.
*
* <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
@@ -594,8 +629,8 @@
* field to provide the user with additional explanation (in addition
* to your component's description) about what is being added.
*
- * <p>If there is already a profile owner active or the caller doesn't have the required
- * permissions, the operation will return a failure result.
+ * <p>If there is already a profile owner active or the caller is not a system app, the
+ * operation will return a failure result.
*/
@SystemApi
public static final String ACTION_SET_PROFILE_OWNER
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
new file mode 100644
index 0000000..af7c053
--- /dev/null
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -0,0 +1,233 @@
+/**
+ * Copyright (C) 2015 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.app.usage;
+
+import android.app.usage.NetworkUsageStats.Bucket;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkIdentity;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * Provides access to network usage history and statistics. Usage data is collected in
+ * discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details.
+ * <p />
+ * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
+ * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except
+ * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user
+ * as the client. In addition tethering usage, usage by removed users and apps, and usage by system
+ * is also included in the results.
+ * <h3>
+ * Summary queries
+ * </h3>
+ * These queries aggregate network usage across the whole interval. Therefore there will be only one
+ * bucket for a particular key and state combination. In case of the user-wide and device-wide
+ * summaries a single bucket containing the totalised network usage is returned.
+ * <h3>
+ * History queries
+ * </h3>
+ * These queries do not aggregate over time but do aggregate over state. Therefore there can be
+ * multiple buckets for a particular key but all Bucket's state is going to be
+ * {@link NetworkUsageStats.Bucket#STATE_ALL}.
+ * <p />
+ * <b>NOTE:</b> This API requires the permission
+ * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
+ * will not be granted to third-party apps. However, declaring the permission implies intention to
+ * use the API and the user of the device can grant permission through the Settings application.
+ * Profile owner apps are automatically granted permission to query data on the profile they manage
+ * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get
+ * access to usage data of the primary user.
+ */
+public class NetworkStatsManager {
+ private final static String TAG = "NetworkStatsManager";
+
+ private final Context mContext;
+
+ /**
+ * {@hide}
+ */
+ public NetworkStatsManager(Context context) {
+ mContext = context;
+ }
+ /**
+ * Query network usage statistics summaries. Result is summarised data usage for the whole
+ * device. Result is a single Bucket aggregated over time, state and uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ Bucket bucket = null;
+ NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime);
+ bucket = stats.getDeviceSummaryForNetwork(startTime, endTime);
+
+ stats.close();
+ return bucket;
+ }
+
+ /**
+ * Query network usage statistics summaries. Result is summarised data usage for all uids
+ * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats stats;
+ stats = new NetworkUsageStats(mContext, template, startTime, endTime);
+ stats.startSummaryEnumeration(startTime, endTime);
+
+ stats.close();
+ return stats.getSummaryAggregate();
+ }
+
+ /**
+ * Query network usage statistics summaries. Result filtered to include only uids belonging to
+ * calling user. Result is aggregated over time, hence all buckets will have the same start and
+ * end timestamps. Not aggregated over state or uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startSummaryEnumeration(startTime, endTime);
+
+ return result;
+ }
+
+ /**
+ * Query network usage statistics details. Only usable for uids belonging to calling user.
+ * Result is aggregated over state but not aggregated over time.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId,
+ long startTime, long endTime, int uid) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startHistoryEnumeration(uid);
+
+ return result;
+ }
+
+ /**
+ * Query network usage statistics details. Result filtered to include only uids belonging to
+ * calling user. Result is aggregated over state but not aggregated over time or uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startUserUidEnumeration();
+ return result;
+ }
+
+ private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ NetworkTemplate template = null;
+ switch (networkType) {
+ case ConnectivityManager.TYPE_MOBILE: {
+ template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
+ } break;
+ case ConnectivityManager.TYPE_WIFI: {
+ template = NetworkTemplate.buildTemplateWifiWildcard();
+ } break;
+ default: {
+ Log.w(TAG, "Cannot create template for network type " + networkType
+ + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) +
+ "'.");
+ }
+ }
+ return template;
+ }
+}
diff --git a/core/java/android/app/usage/NetworkUsageStats.java b/core/java/android/app/usage/NetworkUsageStats.java
new file mode 100644
index 0000000..990d231
--- /dev/null
+++ b/core/java/android/app/usage/NetworkUsageStats.java
@@ -0,0 +1,479 @@
+/**
+ * Copyright (C) 2015 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.app.usage;
+
+import android.content.Context;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+/**
+ * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects
+ * are returned as results to various queries in {@link NetworkStatsManager}.
+ */
+public final class NetworkUsageStats implements AutoCloseable {
+ private final static String TAG = "NetworkUsageStats";
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * Start timestamp of stats collected
+ */
+ private final long mStartTimeStamp;
+
+ /**
+ * End timestamp of stats collected
+ */
+ private final long mEndTimeStamp;
+
+
+ /**
+ * Non-null array indicates the query enumerates over uids.
+ */
+ private int[] mUids;
+
+ /**
+ * Index of the current uid in mUids when doing uid enumeration or a single uid value,
+ * depending on query type.
+ */
+ private int mUidOrUidIndex;
+
+ /**
+ * The session while the query requires it, null if all the stats have been collected or close()
+ * has been called.
+ */
+ private INetworkStatsSession mSession;
+ private NetworkTemplate mTemplate;
+
+ /**
+ * Results of a summary query.
+ */
+ private NetworkStats mSummary = null;
+
+ /**
+ * Results of detail queries.
+ */
+ private NetworkStatsHistory mHistory = null;
+
+ /**
+ * Where we are in enumerating over the current result.
+ */
+ private int mEnumerationIndex = 0;
+
+ /**
+ * Recycling entry objects to prevent heap fragmentation.
+ */
+ private NetworkStats.Entry mRecycledSummaryEntry = null;
+ private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
+
+ /** @hide */
+ NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp,
+ long endTimestamp) throws RemoteException, SecurityException {
+ final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ // Open network stats session
+ mSession = statsService.openSessionForUsageStats(context.getOpPackageName());
+ mCloseGuard.open("close");
+ mTemplate = template;
+ mStartTimeStamp = startTimestamp;
+ mEndTimeStamp = endTimestamp;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // -------------------------BEGINNING OF PUBLIC API-----------------------------------
+
+ /**
+ * Buckets are the smallest elements of a query result. As some dimensions of a result may be
+ * aggregated (e.g. time or state) some values may be equal across all buckets.
+ */
+ public static class Bucket {
+ /**
+ * Combined usage across all other states.
+ */
+ public static final int STATE_ALL = -1;
+
+ /**
+ * Usage not accounted in any other states.
+ */
+ public static final int STATE_DEFAULT = 0x1;
+
+ /**
+ * Foreground usage.
+ */
+ public static final int STATE_FOREGROUND = 0x2;
+
+ /**
+ * Special UID value for removed apps.
+ */
+ public static final int UID_REMOVED = -4;
+
+ /**
+ * Special UID value for data usage by tethering.
+ */
+ public static final int UID_TETHERING = -5;
+
+ private int mUid;
+ private int mState;
+ private long mBeginTimeStamp;
+ private long mEndTimeStamp;
+ private long mRxBytes;
+ private long mRxPackets;
+ private long mTxBytes;
+ private long mTxPackets;
+
+ private static int convertState(int networkStatsSet) {
+ switch (networkStatsSet) {
+ case NetworkStats.SET_ALL : return STATE_ALL;
+ case NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
+ case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND;
+ }
+ return 0;
+ }
+
+ private static int convertUid(int uid) {
+ switch (uid) {
+ case TrafficStats.UID_REMOVED: return UID_REMOVED;
+ case TrafficStats.UID_TETHERING: return UID_TETHERING;
+ }
+ return uid;
+ }
+
+ public Bucket() {
+ }
+
+ /**
+ * Key of the bucket. Usually an app uid or one of the following special values:<p />
+ * <ul>
+ * <li>{@link #UID_REMOVED}</li>
+ * <li>{@link #UID_TETHERING}</li>
+ * <li>{@link android.os.Process#SYSTEM_UID}</li>
+ * </ul>
+ * @return Bucket key.
+ */
+ public int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Usage state. One of the following values:<p/>
+ * <ul>
+ * <li>{@link #STATE_ALL}</li>
+ * <li>{@link #STATE_DEFAULT}</li>
+ * <li>{@link #STATE_FOREGROUND}</li>
+ * </ul>
+ * @return Usage state.
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Start of interval.
+ */
+ public long getStartTimeStamp() {
+ return mBeginTimeStamp;
+ }
+
+ /**
+ * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return End of interval.
+ */
+ public long getEndTimeStamp() {
+ return mEndTimeStamp;
+ }
+
+ /**
+ * Number of bytes received during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of bytes.
+ */
+ public long getRxBytes() {
+ return mRxBytes;
+ }
+
+ /**
+ * Number of bytes transmitted during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of bytes.
+ */
+ public long getTxBytes() {
+ return mTxBytes;
+ }
+
+ /**
+ * Number of packets received during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of packets.
+ */
+ public long getRxPackets() {
+ return mRxPackets;
+ }
+
+ /**
+ * Number of packets transmitted during the bucket's time interval. Statistics are measured
+ * at the network layer, so they include both TCP and UDP usage.
+ * @return Number of packets.
+ */
+ public long getTxPackets() {
+ return mTxPackets;
+ }
+ }
+
+ /**
+ * Fills the recycled bucket with data of the next bin in the enumeration.
+ * @param bucketOut Bucket to be filled with data.
+ * @return true if successfully filled the bucket, false otherwise.
+ */
+ public boolean getNextBucket(Bucket bucketOut) {
+ if (mSummary != null) {
+ return getNextSummaryBucket(bucketOut);
+ } else {
+ return getNextHistoryBucket(bucketOut);
+ }
+ }
+
+ /**
+ * Check if it is possible to ask for a next bucket in the enumeration.
+ * @return true if there is at least one more bucket.
+ */
+ public boolean hasNextBucket() {
+ if (mSummary != null) {
+ return mEnumerationIndex < mSummary.size();
+ } else if (mHistory != null) {
+ return mEnumerationIndex < mHistory.size()
+ || hasNextUid();
+ }
+ return false;
+ }
+
+ /**
+ * Closes the enumeration. Call this method before this object gets out of scope.
+ */
+ @Override
+ public void close() {
+ if (mSession != null) {
+ try {
+ mSession.close();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Otherwise, meh
+ }
+ }
+ mSession = null;
+ if (mCloseGuard != null) {
+ mCloseGuard.close();
+ }
+ }
+
+ // -------------------------END OF PUBLIC API-----------------------------------
+
+ /**
+ * Collects device summary results into a Bucket.
+ * @param startTime
+ * @param endTime
+ * @throws RemoteException
+ */
+ Bucket getDeviceSummaryForNetwork(long startTime, long endTime) throws RemoteException {
+ mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, startTime, endTime);
+
+ // Setting enumeration index beyond end to avoid accidental enumeration over data that does
+ // not belong to the calling user.
+ mEnumerationIndex = mSummary.size();
+
+ return getSummaryAggregate();
+ }
+
+ /**
+ * Collects summary results and sets summary enumeration mode.
+ * @param startTime
+ * @param endTime
+ * @throws RemoteException
+ */
+ void startSummaryEnumeration(long startTime, long endTime) throws RemoteException {
+ mSummary = mSession.getSummaryForAllUid(mTemplate, startTime, endTime, false);
+
+ mEnumerationIndex = 0;
+ }
+
+ /**
+ * Collects history results for uid and resets history enumeration index.
+ */
+ void startHistoryEnumeration(int uid) {
+ mHistory = null;
+ try {
+ mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL,
+ NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
+ setSingleUid(uid);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Leaving mHistory null
+ }
+ mEnumerationIndex = 0;
+ }
+
+ /**
+ * Starts uid enumeration for current user.
+ * @throws RemoteException
+ */
+ void startUserUidEnumeration() throws RemoteException {
+ setUidEnumeration(mSession.getRelevantUids());
+ stepHistory();
+ }
+
+ /**
+ * Steps to next uid in enumeration and collects history for that.
+ */
+ private void stepHistory(){
+ if (hasNextUid()) {
+ stepUid();
+ mHistory = null;
+ try {
+ mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL,
+ NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Leaving mHistory null
+ }
+ mEnumerationIndex = 0;
+ }
+ }
+
+ private void fillBucketFromSummaryEntry(Bucket bucketOut) {
+ bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
+ bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
+ bucketOut.mBeginTimeStamp = mStartTimeStamp;
+ bucketOut.mEndTimeStamp = mEndTimeStamp;
+ bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes;
+ bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets;
+ bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes;
+ bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets;
+ }
+
+ /**
+ * Getting the next item in summary enumeration.
+ * @param bucketOut Next item will be set here.
+ * @return true if a next item could be set.
+ */
+ private boolean getNextSummaryBucket(Bucket bucketOut) {
+ if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
+ mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
+ fillBucketFromSummaryEntry(bucketOut);
+ return true;
+ }
+ return false;
+ }
+
+ Bucket getSummaryAggregate() {
+ if (mSummary == null) {
+ return null;
+ }
+ Bucket bucket = new Bucket();
+ if (mRecycledSummaryEntry == null) {
+ mRecycledSummaryEntry = new NetworkStats.Entry();
+ }
+ mSummary.getTotal(mRecycledSummaryEntry);
+ fillBucketFromSummaryEntry(bucket);
+ return bucket;
+ }
+ /**
+ * Getting the next item in a history enumeration.
+ * @param bucketOut Next item will be set here.
+ * @return true if a next item could be set.
+ */
+ private boolean getNextHistoryBucket(Bucket bucketOut) {
+ if (bucketOut != null && mHistory != null) {
+ if (mEnumerationIndex < mHistory.size()) {
+ mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
+ mRecycledHistoryEntry);
+ bucketOut.mUid = Bucket.convertUid(getUid());
+ bucketOut.mState = Bucket.STATE_ALL;
+ bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
+ bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
+ mRecycledHistoryEntry.bucketDuration;
+ bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes;
+ bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets;
+ bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes;
+ bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets;
+ return true;
+ } else if (hasNextUid()) {
+ stepHistory();
+ return getNextHistoryBucket(bucketOut);
+ }
+ }
+ return false;
+ }
+
+ // ------------------ UID LOGIC------------------------
+
+ private boolean isUidEnumeration() {
+ return mUids != null;
+ }
+
+ private boolean hasNextUid() {
+ return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length;
+ }
+
+ private int getUid() {
+ // Check if uid enumeration.
+ if (isUidEnumeration()) {
+ if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) {
+ throw new IndexOutOfBoundsException(
+ "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length);
+ }
+ return mUids[mUidOrUidIndex];
+ }
+ // Single uid mode.
+ return mUidOrUidIndex;
+ }
+
+ private void setSingleUid(int uid) {
+ mUidOrUidIndex = uid;
+ }
+
+ private void setUidEnumeration(int[] uids) {
+ mUids = uids;
+ mUidOrUidIndex = -1;
+ }
+
+ private void stepUid() {
+ if (mUids != null) {
+ ++mUidOrUidIndex;
+ }
+ }
+}
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 7eae439..0106686 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -25,6 +25,13 @@
* parameters for the scan.
*/
public final class ScanSettings implements Parcelable {
+
+ /**
+ * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for
+ * other scan results without starting BLE scans themselves.
+ */
+ public static final int SCAN_MODE_OPPORTUNISTIC = -1;
+
/**
* Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
* least power.
@@ -177,7 +184,7 @@
* @throws IllegalArgumentException If the {@code scanMode} is invalid.
*/
public Builder setScanMode(int scanMode) {
- if (scanMode < SCAN_MODE_LOW_POWER || scanMode > SCAN_MODE_LOW_LATENCY) {
+ if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
throw new IllegalArgumentException("invalid scan mode " + scanMode);
}
mScanMode = scanMode;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f7566bb..e9d4e59 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2149,7 +2149,7 @@
CONNECTIVITY_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
- //@hide: NETWORK_STATS_SERVICE,
+ NETWORK_STATS_SERVICE,
//@hide: NETWORK_POLICY_SERVICE,
WIFI_SERVICE,
WIFI_PASSPOINT_SERVICE,
@@ -2259,6 +2259,9 @@
* <dd> A {@link android.os.BatteryManager} for managing battery state
* <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
* <dd> A {@link android.app.job.JobScheduler} for managing scheduled tasks
+ * <dt> {@link #NETWORK_STATS_SERVICE} ("netstats")
+ * <dd> A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network
+ * usage statistics.
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -2316,6 +2319,8 @@
* @see android.os.BatteryManager
* @see #JOB_SCHEDULER_SERVICE
* @see android.app.job.JobScheduler
+ * @see #NETWORK_STATS_SERVICE
+ * @see android.app.usage.NetworkStatsManager
*/
public abstract Object getSystemService(@ServiceName @NonNull String name);
@@ -2334,7 +2339,8 @@
* {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
* {@link android.view.inputmethod.InputMethodManager},
* {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
- * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}.
+ * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
+ * {@link android.app.usage.NetworkStatsManager}.
* </p><p>
* Note: System services obtained via this API may be closely associated with
* the Context in which they are obtained from. In general, do not share the
@@ -2563,7 +2569,13 @@
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
- /** {@hide} */
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.app.usage.NetworkStatsManager} for querying network usage stats.
+ *
+ * @see #getSystemService
+ * @see android.app.usage.NetworkStatsManager
+ */
public static final String NETWORK_STATS_SERVICE = "netstats";
/** {@hide} */
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 8f17845..2496e45 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -340,8 +340,6 @@
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
* {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use cleartext traffic.
* Third-party libraries are encouraged to honor this flag as well.
- *
- * @hide
*/
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
@@ -379,7 +377,8 @@
* {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
* {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
* {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
- * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
+ * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_USES_CLEARTEXT_TRAFFIC},
+ * {@link #FLAG_MULTIARCH}.
*/
public int flags = 0;
@@ -655,7 +654,7 @@
}
pw.println(prefix + "dataDir=" + dataDir);
if (sharedLibraryFiles != null) {
- pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
+ pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
}
pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion
+ " versionCode=" + versionCode);
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index a6c3ea4..88fa339 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -54,11 +54,13 @@
// Looper associated with the context in which this instance was created.
private final Looper mMainLooper;
private final int mTargetSdkLevel;
+ private final String mPackageName;
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
mMainLooper = mainLooper;
mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
+ mPackageName = context.getPackageName();
synchronized(sSensorModuleLock) {
if (!sSensorModuleInitialized) {
sSensorModuleInitialized = true;
@@ -117,14 +119,14 @@
if (queue == null) {
Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
queue = new SensorEventQueue(listener, looper, this);
- if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
+ if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
queue.dispose();
return false;
}
mSensorListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
+ return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
}
}
}
@@ -165,14 +167,14 @@
TriggerEventQueue queue = mTriggerListeners.get(listener);
if (queue == null) {
queue = new TriggerEventQueue(listener, mMainLooper, this);
- if (!queue.addSensor(sensor, 0, 0, 0)) {
+ if (!queue.addSensor(sensor, 0, 0)) {
queue.dispose();
return false;
}
mTriggerListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, 0, 0, 0);
+ return queue.addSensor(sensor, 0, 0);
}
}
}
@@ -223,9 +225,9 @@
*/
private static abstract class BaseEventQueue {
private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
- float[] scratch);
+ float[] scratch, String packageName);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
- int maxBatchReportLatencyUs, int reservedFlags);
+ int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
private static native void nativeDestroySensorEventQueue(long eventQ);
private static native int nativeFlushSensor(long eventQ);
@@ -238,7 +240,8 @@
protected final SystemSensorManager mManager;
BaseEventQueue(Looper looper, SystemSensorManager manager) {
- nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
+ nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch,
+ manager.mPackageName);
mCloseGuard.open("dispose");
mManager = manager;
}
@@ -248,7 +251,7 @@
}
public boolean addSensor(
- Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) {
+ Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
// Check if already present.
int handle = sensor.getHandle();
if (mActiveSensors.get(handle)) return false;
@@ -256,10 +259,10 @@
// Get ready to receive events before calling enable.
mActiveSensors.put(handle, true);
addSensorEvent(sensor);
- if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) {
+ if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
// Try continuous mode if batching fails.
if (maxBatchReportLatencyUs == 0 ||
- maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) {
+ maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
removeSensor(sensor, false);
return false;
}
@@ -328,11 +331,11 @@
}
private int enableSensor(
- Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) {
+ Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
if (nSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
- maxBatchReportLatencyUs, reservedFlags);
+ maxBatchReportLatencyUs);
}
private int disableSensor(Sensor sensor) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 34a0727..a0e2bf8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2337,7 +2337,7 @@
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
* <p>
- * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+ * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or
* {@link Network#openConnection(java.net.URL)} then you must get a
* ConnectivityManager instance before doing so.
*/
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 2c3881c..6436e42 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -27,6 +27,14 @@
/** Start a statistics query session. */
INetworkStatsSession openSession();
+ /** Start a statistics query session. If calling package is profile or device owner then it is
+ * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If
+ * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then
+ * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted
+ * READ_NETWORK_USAGE_STATS is checked for.
+ */
+ INetworkStatsSession openSessionForUsageStats(String callingPackage);
+
/** Return network layer usage total for traffic that matches template. */
long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl
index 1596fa2..7bcb043 100644
--- a/core/java/android/net/INetworkStatsSession.aidl
+++ b/core/java/android/net/INetworkStatsSession.aidl
@@ -23,6 +23,9 @@
/** {@hide} */
interface INetworkStatsSession {
+ /** Return device aggregated network layer usage summary for traffic that matches template. */
+ NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end);
+
/** Return network layer usage summary for traffic that matches template. */
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
/** Return historical network layer stats for traffic that matches template. */
@@ -33,6 +36,9 @@
/** Return historical network layer stats for specific UID traffic that matches template. */
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+ /** Return array of uids that have stats and are accessible to the calling user */
+ int[] getRelevantUids();
+
void close();
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a7f9c5b..8c8bfab 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -148,9 +148,9 @@
*/
public static final int NET_CAPABILITY_TRUSTED = 14;
- /*
+ /**
* Indicates that this network is not a VPN. This capability is set by default and should be
- * explicitly cleared when creating VPN networks.
+ * explicitly cleared for VPN networks.
*/
public static final int NET_CAPABILITY_NOT_VPN = 15;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 26e6b850..8b3ecae 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -29,6 +29,7 @@
import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
+import android.util.ArrayMap;
import android.util.Printer;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -283,21 +284,21 @@
*
* @return a Map from Strings to Uid.Wakelock objects.
*/
- public abstract Map<String, ? extends Wakelock> getWakelockStats();
+ public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
/**
* Returns a mapping containing sync statistics.
*
* @return a Map from Strings to Timer objects.
*/
- public abstract Map<String, ? extends Timer> getSyncStats();
+ public abstract ArrayMap<String, ? extends Timer> getSyncStats();
/**
* Returns a mapping containing scheduled job statistics.
*
* @return a Map from Strings to Timer objects.
*/
- public abstract Map<String, ? extends Timer> getJobStats();
+ public abstract ArrayMap<String, ? extends Timer> getJobStats();
/**
* The statistics associated with a particular wake lock.
@@ -323,14 +324,14 @@
*
* @return a Map from Strings to Uid.Proc objects.
*/
- public abstract Map<String, ? extends Proc> getProcessStats();
+ public abstract ArrayMap<String, ? extends Proc> getProcessStats();
/**
* Returns a mapping containing package statistics.
*
* @return a Map from Strings to Uid.Pkg objects.
*/
- public abstract Map<String, ? extends Pkg> getPackageStats();
+ public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
/**
* {@hide}
@@ -501,17 +502,16 @@
public static abstract class Pkg {
/**
- * Returns the number of times this package has done something that could wake up the
- * device from sleep.
- *
- * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+ * Returns information about all wakeup alarms that have been triggered for this
+ * package. The mapping keys are tag names for the alarms, the counter contains
+ * the number of times the alarm was triggered while on battery.
*/
- public abstract int getWakeups(int which);
+ public abstract ArrayMap<String, ? extends Counter> getWakeupAlarmStats();
/**
* Returns a mapping containing service statistics.
*/
- public abstract Map<String, ? extends Serv> getServiceStats();
+ public abstract ArrayMap<String, ? extends Serv> getServiceStats();
/**
* The statistics associated with a particular service.
@@ -1352,7 +1352,7 @@
int idx = code&HistoryItem.EVENT_TYPE_MASK;
HashMap<String, SparseIntArray> active = mActiveEvents[idx];
if (active == null) {
- active = new HashMap<String, SparseIntArray>();
+ active = new HashMap<>();
mActiveEvents[idx] = active;
}
SparseIntArray uids = active.get(name);
@@ -2382,12 +2382,12 @@
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
- StringBuilder sb = new StringBuilder(128);
+ final StringBuilder sb = new StringBuilder(128);
- SparseArray<? extends Uid> uidStats = getUidStats();
+ final SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
- String category = STAT_NAMES[which];
+ final String category = STAT_NAMES[which];
// Dump "battery" stat
dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
@@ -2402,37 +2402,35 @@
long partialWakeLockTimeTotal = 0;
for (int iu = 0; iu < NU; iu++) {
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
- : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
-
- Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
- if (fullWakeTimer != null) {
- fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
- which);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
- Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
- if (partialWakeTimer != null) {
- partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- }
+ final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+ if (fullWakeTimer != null) {
+ fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
+ which);
+ }
+
+ final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+ if (partialWakeTimer != null) {
+ partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
}
}
}
- long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
// Dump network stats
dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA,
@@ -2544,7 +2542,7 @@
}
if (reqUid < 0) {
- Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
+ final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
for (Map.Entry<String, ? extends Timer> ent : kernelWakelocks.entrySet()) {
sb.setLength(0);
@@ -2553,7 +2551,7 @@
sb.toString());
}
}
- Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+ final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
if (wakeupReasons.size() > 0) {
for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
// Not doing the regular wake lock formatting to remain compatible
@@ -2566,10 +2564,10 @@
}
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+ final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
- List<BatterySipper> sippers = helper.getUsageList();
+ final List<BatterySipper> sippers = helper.getUsageList();
if (sippers != null && sippers.size() > 0) {
dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()),
@@ -2577,7 +2575,7 @@
BatteryStatsHelper.makemAh(helper.getMinDrainedPower()),
BatteryStatsHelper.makemAh(helper.getMaxDrainedPower()));
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
int uid = 0;
String label;
switch (bs.drainType) {
@@ -2629,22 +2627,22 @@
if (reqUid >= 0 && uid != reqUid) {
continue;
}
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
// Dump Network stats per uid, if any
- long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long mobileActiveTime = u.getMobileRadioActiveTime(which);
- int mobileActiveCount = u.getMobileRadioActiveCount(which);
- long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
- long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
- long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
- int wifiScanCount = u.getWifiScanCount(which);
- long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long mobileActiveTime = u.getMobileRadioActiveTime(which);
+ final int mobileActiveCount = u.getMobileRadioActiveCount(which);
+ final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+ final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+ final int wifiScanCount = u.getWifiScanCount(which);
+ final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
|| mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
@@ -2675,93 +2673,90 @@
}
}
- Map<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
- String linePrefix = "";
- sb.setLength(0);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL),
- rawRealtime, "f", which, linePrefix);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL),
- rawRealtime, "p", which, linePrefix);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW),
- rawRealtime, "w", which, linePrefix);
-
- // Only log if we had at lease one wakelock...
- if (sb.length() > 0) {
- String name = ent.getKey();
- if (name.indexOf(',') >= 0) {
- name = name.replace(',', '_');
- }
- dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
+ final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+ String linePrefix = "";
+ sb.setLength(0);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL),
+ rawRealtime, "f", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL),
+ rawRealtime, "p", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW),
+ rawRealtime, "w", which, linePrefix);
+
+ // Only log if we had at lease one wakelock...
+ if (sb.length() > 0) {
+ String name = wakelocks.keyAt(iw);
+ if (name.indexOf(',') >= 0) {
+ name = name.replace(',', '_');
}
+ dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
}
}
- Map<String, ? extends Timer> syncs = u.getSyncStats();
- if (syncs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- if (totalTime != 0) {
- dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count);
- }
+ final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+ for (int isy=syncs.size()-1; isy>=0; isy--) {
+ final Timer timer = syncs.valueAt(isy);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, SYNC_DATA, syncs.keyAt(isy), totalTime, count);
}
}
- Map<String, ? extends Timer> jobs = u.getJobStats();
- if (jobs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- if (totalTime != 0) {
- dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count);
- }
+ final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+ for (int ij=jobs.size()-1; ij>=0; ij--) {
+ final Timer timer = jobs.valueAt(ij);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, JOB_DATA, jobs.keyAt(ij), totalTime, count);
}
}
- SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
- int NSE = sensors.size();
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ final int NSE = sensors.size();
for (int ise=0; ise<NSE; ise++) {
- Uid.Sensor se = sensors.valueAt(ise);
- int sensorNumber = sensors.keyAt(ise);
- Timer timer = se.getSensorTime();
+ final Uid.Sensor se = sensors.valueAt(ise);
+ final int sensorNumber = sensors.keyAt(ise);
+ final Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = timer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
}
}
}
- Timer vibTimer = u.getVibratorOnTimer();
+ final Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = vibTimer.getCountLocked(which);
+ final long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = vibTimer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count);
}
}
- Timer fgTimer = u.getForegroundActivityTimer();
+ final Timer fgTimer = u.getForegroundActivityTimer();
if (fgTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = fgTimer.getCountLocked(which);
+ final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = fgTimer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
}
}
- Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
+ final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
long totalStateTime = 0;
for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) {
totalStateTime += u.getProcessStateTime(ips, rawRealtime, which);
@@ -2771,50 +2766,48 @@
dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes);
}
- Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
- if (processStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
- : processStats.entrySet()) {
- Uid.Proc ps = ent.getValue();
+ final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+ = u.getProcessStats();
+ for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+ final Uid.Proc ps = processStats.valueAt(ipr);
- final long userMillis = ps.getUserTime(which);
- final long systemMillis = ps.getSystemTime(which);
- final long foregroundMillis = ps.getForegroundTime(which);
- final int starts = ps.getStarts(which);
- final int numCrashes = ps.getNumCrashes(which);
- final int numAnrs = ps.getNumAnrs(which);
+ final long userMillis = ps.getUserTime(which);
+ final long systemMillis = ps.getSystemTime(which);
+ final long foregroundMillis = ps.getForegroundTime(which);
+ final int starts = ps.getStarts(which);
+ final int numCrashes = ps.getNumCrashes(which);
+ final int numAnrs = ps.getNumAnrs(which);
- if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
- || starts != 0 || numAnrs != 0 || numCrashes != 0) {
- dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
- systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
- }
+ if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
+ || starts != 0 || numAnrs != 0 || numCrashes != 0) {
+ dumpLine(pw, uid, category, PROCESS_DATA, processStats.keyAt(ipr), userMillis,
+ systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
}
}
- Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
- if (packageStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
- : packageStats.entrySet()) {
-
- Uid.Pkg ps = ent.getValue();
- int wakeups = ps.getWakeups(which);
- Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
- : serviceStats.entrySet()) {
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(batteryUptime, which);
- int starts = ss.getStarts(which);
- int launches = ss.getLaunches(which);
- if (startTime != 0 || starts != 0 || launches != 0) {
- dumpLine(pw, uid, category, APK_DATA,
- wakeups, // wakeup alarms
- ent.getKey(), // Apk
- sent.getKey(), // service
- startTime / 1000, // time spent started, in ms
- starts,
- launches);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+ = u.getPackageStats();
+ for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+ final Uid.Pkg ps = packageStats.valueAt(ipkg);
+ int wakeups = 0;
+ final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+ for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+ wakeups += alarms.valueAt(iwa).getCountLocked(which);
+ }
+ final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+ final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+ final long startTime = ss.getStartTime(batteryUptime, which);
+ final int starts = ss.getStarts(which);
+ final int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ dumpLine(pw, uid, category, APK_DATA,
+ wakeups, // wakeup alarms
+ packageStats.keyAt(ipkg), // Apk
+ serviceStats.keyAt(isvc), // service
+ startTime / 1000, // time spent started, in ms
+ starts,
+ launches);
}
}
}
@@ -2863,9 +2856,9 @@
final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
- StringBuilder sb = new StringBuilder(128);
+ final StringBuilder sb = new StringBuilder(128);
- SparseArray<? extends Uid> uidStats = getUidStats();
+ final SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
sb.setLength(0);
@@ -2992,7 +2985,7 @@
sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
sb.append(") "); sb.append(getPhoneOnCount(which)); sb.append("x");
}
- int connChanges = getNumConnectivityChange(which);
+ final int connChanges = getNumConnectivityChange(which);
if (connChanges != 0) {
pw.print(prefix);
pw.print(" Connectivity changes: "); pw.println(connChanges);
@@ -3002,50 +2995,48 @@
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
- final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
+ final ArrayList<TimerEntry> timers = new ArrayList<>();
for (int iu = 0; iu < NU; iu++) {
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
- : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
-
- Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
- if (fullWakeTimer != null) {
- fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
- Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
- if (partialWakeTimer != null) {
- long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- if (totalTimeMicros > 0) {
- if (reqUid < 0) {
- // Only show the ordered list of all wake
- // locks if the caller is not asking for data
- // about a specific uid.
- timers.add(new TimerEntry(ent.getKey(), u.getUid(),
- partialWakeTimer, totalTimeMicros));
- }
- partialWakeLockTimeTotalMicros += totalTimeMicros;
+ final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+ if (fullWakeTimer != null) {
+ fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
+ }
+
+ final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+ if (partialWakeTimer != null) {
+ final long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
+ if (totalTimeMicros > 0) {
+ if (reqUid < 0) {
+ // Only show the ordered list of all wake
+ // locks if the caller is not asking for data
+ // about a specific uid.
+ timers.add(new TimerEntry(wakelocks.keyAt(iw), u.getUid(),
+ partialWakeTimer, totalTimeMicros));
}
+ partialWakeLockTimeTotalMicros += totalTimeMicros;
}
}
}
}
- long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
if (fullWakeLockTimeTotalMicros != 0) {
sb.setLength(0);
@@ -3242,9 +3233,9 @@
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
- final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+ final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
+ final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
sb.setLength(0);
@@ -3367,7 +3358,7 @@
pw.println();
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+ final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
@@ -3382,7 +3373,7 @@
}
pw.println();
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
switch (bs.drainType) {
case IDLE:
pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.value);
@@ -3439,7 +3430,7 @@
pw.print(prefix); pw.println(" Per-app mobile ms per packet:");
long totalTime = 0;
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
sb.setLength(0);
sb.append(prefix); sb.append(" Uid ");
UserHandle.formatUid(sb, bs.uidObj.getUid());
@@ -3476,12 +3467,14 @@
};
if (reqUid < 0) {
- Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+ final Map<String, ? extends BatteryStats.Timer> kernelWakelocks
+ = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
- final ArrayList<TimerEntry> ktimers = new ArrayList<TimerEntry>();
- for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
- BatteryStats.Timer timer = ent.getValue();
- long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
+ final ArrayList<TimerEntry> ktimers = new ArrayList<>();
+ for (Map.Entry<String, ? extends BatteryStats.Timer> ent
+ : kernelWakelocks.entrySet()) {
+ final BatteryStats.Timer timer = ent.getValue();
+ final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
if (totalTimeMillis > 0) {
ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
}
@@ -3490,7 +3483,7 @@
Collections.sort(ktimers, timerComparator);
pw.print(prefix); pw.println(" All kernel wake locks:");
for (int i=0; i<ktimers.size(); i++) {
- TimerEntry timer = ktimers.get(i);
+ final TimerEntry timer = ktimers.get(i);
String linePrefix = ": ";
sb.setLength(0);
sb.append(prefix);
@@ -3526,12 +3519,12 @@
pw.println();
}
- Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+ final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
if (wakeupReasons.size() > 0) {
pw.print(prefix); pw.println(" All wakeup reasons:");
- final ArrayList<TimerEntry> reasons = new ArrayList<TimerEntry>();
+ final ArrayList<TimerEntry> reasons = new ArrayList<>();
for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
- Timer timer = ent.getValue();
+ final Timer timer = ent.getValue();
reasons.add(new TimerEntry(ent.getKey(), 0, timer,
timer.getCountLocked(which)));
}
@@ -3557,7 +3550,7 @@
continue;
}
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
pw.print(prefix);
pw.print(" ");
@@ -3565,20 +3558,20 @@
pw.println(":");
boolean uidActivity = false;
- long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
- int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
- long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
- long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
- long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
- int wifiScanCount = u.getWifiScanCount(which);
- long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
+ final int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
+ final long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+ final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+ final int wifiScanCount = u.getWifiScanCount(which);
+ final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (mobileRxBytes > 0 || mobileTxBytes > 0
|| mobileRxPackets > 0 || mobileTxPackets > 0) {
@@ -3636,7 +3629,7 @@
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
- int val = u.getUserActivityCount(i, which);
+ final int val = u.getUserActivityCount(i, which);
if (val != 0) {
if (!hasData) {
sb.setLength(0);
@@ -3655,125 +3648,121 @@
}
}
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- long totalFull = 0, totalPartial = 0, totalWindow = 0;
- int count = 0;
- for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
- String linePrefix = ": ";
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Wake lock ");
- sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
- "full", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
- "partial", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
- "window", which, linePrefix);
- if (true || !linePrefix.equals(": ")) {
- sb.append(" realtime");
- // Only print out wake locks that were held
- pw.println(sb.toString());
- uidActivity = true;
- count++;
- }
- totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
- rawRealtime, which);
- totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
- rawRealtime, which);
- totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
- rawRealtime, which);
- }
- if (count > 1) {
- if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" TOTAL wake: ");
- boolean needComma = false;
- if (totalFull != 0) {
- needComma = true;
- formatTimeMs(sb, totalFull);
- sb.append("full");
- }
- if (totalPartial != 0) {
- if (needComma) {
- sb.append(", ");
- }
- needComma = true;
- formatTimeMs(sb, totalPartial);
- sb.append("partial");
- }
- if (totalWindow != 0) {
- if (needComma) {
- sb.append(", ");
- }
- needComma = true;
- formatTimeMs(sb, totalWindow);
- sb.append("window");
- }
- sb.append(" realtime");
- pw.println(sb.toString());
- }
- }
- }
-
- Map<String, ? extends Timer> syncs = u.getSyncStats();
- if (syncs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Sync ");
- sb.append(ent.getKey());
- sb.append(": ");
- if (totalTime != 0) {
- formatTimeMs(sb, totalTime);
- sb.append("realtime (");
- sb.append(count);
- sb.append(" times)");
- } else {
- sb.append("(not used)");
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0;
+ int countWakelock = 0;
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+ String linePrefix = ": ";
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Wake lock ");
+ sb.append(wakelocks.keyAt(iw));
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
+ "full", which, linePrefix);
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
+ "partial", which, linePrefix);
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
+ "window", which, linePrefix);
+ if (true || !linePrefix.equals(": ")) {
+ sb.append(" realtime");
+ // Only print out wake locks that were held
pw.println(sb.toString());
uidActivity = true;
+ countWakelock++;
}
+ totalFullWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
+ rawRealtime, which);
+ totalPartialWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
+ rawRealtime, which);
+ totalWindowWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
+ rawRealtime, which);
}
-
- Map<String, ? extends Timer> jobs = u.getJobStats();
- if (jobs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
+ if (countWakelock > 1) {
+ if (totalFullWakelock != 0 || totalPartialWakelock != 0
+ || totalWindowWakelock != 0) {
sb.setLength(0);
sb.append(prefix);
- sb.append(" Job ");
- sb.append(ent.getKey());
- sb.append(": ");
- if (totalTime != 0) {
- formatTimeMs(sb, totalTime);
- sb.append("realtime (");
- sb.append(count);
- sb.append(" times)");
- } else {
- sb.append("(not used)");
+ sb.append(" TOTAL wake: ");
+ boolean needComma = false;
+ if (totalFullWakelock != 0) {
+ needComma = true;
+ formatTimeMs(sb, totalFullWakelock);
+ sb.append("full");
}
+ if (totalPartialWakelock != 0) {
+ if (needComma) {
+ sb.append(", ");
+ }
+ needComma = true;
+ formatTimeMs(sb, totalPartialWakelock);
+ sb.append("partial");
+ }
+ if (totalWindowWakelock != 0) {
+ if (needComma) {
+ sb.append(", ");
+ }
+ needComma = true;
+ formatTimeMs(sb, totalWindowWakelock);
+ sb.append("window");
+ }
+ sb.append(" realtime");
pw.println(sb.toString());
- uidActivity = true;
}
}
- SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
- int NSE = sensors.size();
+ final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+ for (int isy=syncs.size()-1; isy>=0; isy--) {
+ final Timer timer = syncs.valueAt(isy);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Sync ");
+ sb.append(syncs.keyAt(isy));
+ sb.append(": ");
+ if (totalTime != 0) {
+ formatTimeMs(sb, totalTime);
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ } else {
+ sb.append("(not used)");
+ }
+ pw.println(sb.toString());
+ uidActivity = true;
+ }
+
+ final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+ for (int ij=jobs.size()-1; ij>=0; ij--) {
+ final Timer timer = jobs.valueAt(ij);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Job ");
+ sb.append(jobs.keyAt(ij));
+ sb.append(": ");
+ if (totalTime != 0) {
+ formatTimeMs(sb, totalTime);
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ } else {
+ sb.append("(not used)");
+ }
+ pw.println(sb.toString());
+ uidActivity = true;
+ }
+
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ final int NSE = sensors.size();
for (int ise=0; ise<NSE; ise++) {
- Uid.Sensor se = sensors.valueAt(ise);
- int sensorNumber = sensors.keyAt(ise);
+ final Uid.Sensor se = sensors.valueAt(ise);
+ final int sensorNumber = sensors.keyAt(ise);
sb.setLength(0);
sb.append(prefix);
sb.append(" Sensor ");
@@ -3785,12 +3774,12 @@
}
sb.append(": ");
- Timer timer = se.getSensorTime();
+ final Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(
+ final long totalTime = (timer.getTotalTimeLocked(
rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
+ final int count = timer.getCountLocked(which);
//timer.logState();
if (totalTime != 0) {
formatTimeMs(sb, totalTime);
@@ -3808,12 +3797,12 @@
uidActivity = true;
}
- Timer vibTimer = u.getVibratorOnTimer();
+ final Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (vibTimer.getTotalTimeLocked(
+ final long totalTime = (vibTimer.getTotalTimeLocked(
rawRealtime, which) + 500) / 1000;
- int count = vibTimer.getCountLocked(which);
+ final int count = vibTimer.getCountLocked(which);
//timer.logState();
if (totalTime != 0) {
sb.setLength(0);
@@ -3828,11 +3817,12 @@
}
}
- Timer fgTimer = u.getForegroundActivityTimer();
+ final Timer fgTimer = u.getForegroundActivityTimer();
if (fgTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = fgTimer.getCountLocked(which);
+ final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = fgTimer.getCountLocked(which);
if (totalTime != 0) {
sb.setLength(0);
sb.append(prefix);
@@ -3862,126 +3852,122 @@
}
}
- Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
- if (processStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
- : processStats.entrySet()) {
- Uid.Proc ps = ent.getValue();
- long userTime;
- long systemTime;
- long foregroundTime;
- int starts;
- int numExcessive;
+ final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+ = u.getProcessStats();
+ for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+ final Uid.Proc ps = processStats.valueAt(ipr);
+ long userTime;
+ long systemTime;
+ long foregroundTime;
+ int starts;
+ int numExcessive;
- userTime = ps.getUserTime(which);
- systemTime = ps.getSystemTime(which);
- foregroundTime = ps.getForegroundTime(which);
- starts = ps.getStarts(which);
- final int numCrashes = ps.getNumCrashes(which);
- final int numAnrs = ps.getNumAnrs(which);
- numExcessive = which == STATS_SINCE_CHARGED
- ? ps.countExcessivePowers() : 0;
+ userTime = ps.getUserTime(which);
+ systemTime = ps.getSystemTime(which);
+ foregroundTime = ps.getForegroundTime(which);
+ starts = ps.getStarts(which);
+ final int numCrashes = ps.getNumCrashes(which);
+ final int numAnrs = ps.getNumAnrs(which);
+ numExcessive = which == STATS_SINCE_CHARGED
+ ? ps.countExcessivePowers() : 0;
- if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
- || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
- sb.setLength(0);
- sb.append(prefix); sb.append(" Proc ");
- sb.append(ent.getKey()); sb.append(":\n");
- sb.append(prefix); sb.append(" CPU: ");
- formatTimeMs(sb, userTime); sb.append("usr + ");
- formatTimeMs(sb, systemTime); sb.append("krn ; ");
- formatTimeMs(sb, foregroundTime); sb.append("fg");
- if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
- sb.append("\n"); sb.append(prefix); sb.append(" ");
- boolean hasOne = false;
- if (starts != 0) {
- hasOne = true;
- sb.append(starts); sb.append(" starts");
- }
- if (numCrashes != 0) {
- if (hasOne) {
- sb.append(", ");
- }
- hasOne = true;
- sb.append(numCrashes); sb.append(" crashes");
- }
- if (numAnrs != 0) {
- if (hasOne) {
- sb.append(", ");
- }
- sb.append(numAnrs); sb.append(" anrs");
- }
+ if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
+ || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
+ sb.setLength(0);
+ sb.append(prefix); sb.append(" Proc ");
+ sb.append(processStats.keyAt(ipr)); sb.append(":\n");
+ sb.append(prefix); sb.append(" CPU: ");
+ formatTimeMs(sb, userTime); sb.append("usr + ");
+ formatTimeMs(sb, systemTime); sb.append("krn ; ");
+ formatTimeMs(sb, foregroundTime); sb.append("fg");
+ if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
+ sb.append("\n"); sb.append(prefix); sb.append(" ");
+ boolean hasOne = false;
+ if (starts != 0) {
+ hasOne = true;
+ sb.append(starts); sb.append(" starts");
}
- pw.println(sb.toString());
- for (int e=0; e<numExcessive; e++) {
- Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
- if (ew != null) {
- pw.print(prefix); pw.print(" * Killed for ");
- if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
- pw.print("wake lock");
- } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
- pw.print("cpu");
- } else {
- pw.print("unknown");
- }
- pw.print(" use: ");
- TimeUtils.formatDuration(ew.usedTime, pw);
- pw.print(" over ");
- TimeUtils.formatDuration(ew.overTime, pw);
- if (ew.overTime != 0) {
- pw.print(" (");
- pw.print((ew.usedTime*100)/ew.overTime);
- pw.println("%)");
- }
+ if (numCrashes != 0) {
+ if (hasOne) {
+ sb.append(", ");
}
+ hasOne = true;
+ sb.append(numCrashes); sb.append(" crashes");
}
- uidActivity = true;
- }
- }
- }
-
- Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
- if (packageStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
- : packageStats.entrySet()) {
- pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":");
- boolean apkActivity = false;
- Uid.Pkg ps = ent.getValue();
- int wakeups = ps.getWakeups(which);
- if (wakeups != 0) {
- pw.print(prefix); pw.print(" ");
- pw.print(wakeups); pw.println(" wakeup alarms");
- apkActivity = true;
- }
- Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
- if (serviceStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
- : serviceStats.entrySet()) {
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(batteryUptime, which);
- int starts = ss.getStarts(which);
- int launches = ss.getLaunches(which);
- if (startTime != 0 || starts != 0 || launches != 0) {
- sb.setLength(0);
- sb.append(prefix); sb.append(" Service ");
- sb.append(sent.getKey()); sb.append(":\n");
- sb.append(prefix); sb.append(" Created for: ");
- formatTimeMs(sb, startTime / 1000);
- sb.append("uptime\n");
- sb.append(prefix); sb.append(" Starts: ");
- sb.append(starts);
- sb.append(", launches: "); sb.append(launches);
- pw.println(sb.toString());
- apkActivity = true;
+ if (numAnrs != 0) {
+ if (hasOne) {
+ sb.append(", ");
}
+ sb.append(numAnrs); sb.append(" anrs");
}
}
- if (!apkActivity) {
- pw.print(prefix); pw.println(" (nothing executed)");
+ pw.println(sb.toString());
+ for (int e=0; e<numExcessive; e++) {
+ Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
+ if (ew != null) {
+ pw.print(prefix); pw.print(" * Killed for ");
+ if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
+ pw.print("wake lock");
+ } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
+ pw.print("cpu");
+ } else {
+ pw.print("unknown");
+ }
+ pw.print(" use: ");
+ TimeUtils.formatDuration(ew.usedTime, pw);
+ pw.print(" over ");
+ TimeUtils.formatDuration(ew.overTime, pw);
+ if (ew.overTime != 0) {
+ pw.print(" (");
+ pw.print((ew.usedTime*100)/ew.overTime);
+ pw.println("%)");
+ }
+ }
}
uidActivity = true;
}
}
+
+ final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+ = u.getPackageStats();
+ for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+ pw.print(prefix); pw.print(" Apk "); pw.print(packageStats.keyAt(ipkg));
+ pw.println(":");
+ boolean apkActivity = false;
+ final Uid.Pkg ps = packageStats.valueAt(ipkg);
+ final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+ for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+ pw.print(prefix); pw.print(" Wakeup alarm ");
+ pw.print(alarms.keyAt(iwa)); pw.print(": ");
+ pw.print(alarms.valueAt(iwa).getCountLocked(which));
+ pw.println(" times");
+ apkActivity = true;
+ }
+ final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+ final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+ final long startTime = ss.getStartTime(batteryUptime, which);
+ final int starts = ss.getStarts(which);
+ final int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ sb.setLength(0);
+ sb.append(prefix); sb.append(" Service ");
+ sb.append(serviceStats.keyAt(isvc)); sb.append(":\n");
+ sb.append(prefix); sb.append(" Created for: ");
+ formatTimeMs(sb, startTime / 1000);
+ sb.append("uptime\n");
+ sb.append(prefix); sb.append(" Starts: ");
+ sb.append(starts);
+ sb.append(", launches: "); sb.append(launches);
+ pw.println(sb.toString());
+ apkActivity = true;
+ }
+ }
+ if (!apkActivity) {
+ pw.print(prefix); pw.println(" (nothing executed)");
+ }
+ uidActivity = true;
+ }
if (!uidActivity) {
pw.print(prefix); pw.println(" (nothing executed)");
}
@@ -4498,7 +4484,6 @@
return true;
}
- public static final int DUMP_UNPLUGGED_ONLY = 1<<0;
public static final int DUMP_CHARGED_ONLY = 1<<1;
public static final int DUMP_DAILY_ONLY = 1<<2;
public static final int DUMP_HISTORY_ONLY = 1<<3;
@@ -4647,7 +4632,7 @@
prepareForDumpLocked();
final boolean filtering = (flags
- & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+ & (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
final long historyTotalSize = getHistoryTotalSize();
@@ -4691,7 +4676,7 @@
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4769,7 +4754,7 @@
LevelStepTracker csteps = getDailyChargeLevelStepTracker();
ArrayList<PackageChange> pkgc = getDailyPackageChanges();
if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0 || pkgc != null) {
- if ((flags&DUMP_DAILY_ONLY) != 0) {
+ if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
if (dumpDurationSteps(pw, " ", " Current daily discharge step durations:",
dsteps, false)) {
dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps,
@@ -4801,7 +4786,7 @@
pw.print(" to ");
pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString());
pw.println(":");
- if ((flags&DUMP_DAILY_ONLY) != 0) {
+ if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
if (dumpDurationSteps(pw, " ",
" Discharge step durations:", dit.mDischargeSteps, false)) {
dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps,
@@ -4830,11 +4815,6 @@
(flags&DUMP_DEVICE_WIFI_ONLY) != 0);
pw.println();
}
- if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
- pw.println("Statistics since last unplugged:");
- dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid,
- (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
- }
}
@SuppressWarnings("unused")
@@ -4848,7 +4828,7 @@
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
final boolean filtering = (flags &
- (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+ (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
if (startIteratingHistoryLocked()) {
@@ -4874,7 +4854,7 @@
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4924,9 +4904,5 @@
dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1,
(flags&DUMP_DEVICE_WIFI_ONLY) != 0);
}
- if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
- dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1,
- (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
- }
}
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 418641f..804d3d0 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -51,6 +51,7 @@
void setStayOnSetting(int val);
void boostScreenBrightness(long time);
+ boolean isScreenBrightnessBoosted();
// temporarily overrides the screen brightness settings to allow the user to
// see the effect of a settings change without applying it immediately
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 81745b3..01c9a21 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -712,6 +712,22 @@
}
/**
+ * Returns whether the screen brightness is currently boosted to maximum, caused by a call
+ * to {@link #boostScreenBrightness(long)}.
+ * @return {@code True} if the screen brightness is currently boosted. {@code False} otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isScreenBrightnessBoosted() {
+ try {
+ return mService.isScreenBrightnessBoosted();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Sets the brightness of the backlights (screen, keyboard, button).
* <p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -917,6 +933,16 @@
public static final String EXTRA_POWER_SAVE_MODE = "mode";
/**
+ * Intent that is broadcast when the state of {@link #isScreenBrightnessBoosted()} has changed.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @hide
+ **/
+ @SystemApi
+ public static final String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED
+ = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
+
+ /**
* A wake lock is a mechanism to indicate that your application needs
* to have the device stay on.
* <p>
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 74b0a1c..e4a6f07 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4809,6 +4809,14 @@
Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
/**
+ * The content:// style URI for this table in corp profile
+ *
+ * @hide
+ */
+ public static final Uri CORP_CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities_corp");
+
+ /**
* The content:// style URI for this table, specific to the user's profile.
*/
public static final Uri PROFILE_CONTENT_URI =
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index ac6bbb7..d24bc13 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -19,6 +19,7 @@
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.security.KeystoreArguments;
@@ -61,11 +62,12 @@
int addRngEntropy(in byte[] data);
int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags,
out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in byte[] clientId,
- in byte[] appId, out KeyCharacteristics characteristics);
+ int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
+ out KeyCharacteristics characteristics);
int importKey(String alias, in KeymasterArguments arguments, int format,
in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId);
+ ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
+ in KeymasterBlob appId);
OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
in KeymasterArguments params, out KeymasterArguments operationParams);
OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index c7274e8..0b3bf453 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -19,48 +19,57 @@
/**
* Network security policy.
*
- * @hide
+ * <p>Network stacks/components should honor this policy to make it possible to centrally control
+ * the relevant aspects of network security behavior.
+ *
+ * <p>The policy currently consists of a single flag: whether cleartext network traffic is
+ * permitted. See {@link #isCleartextTrafficPermitted()}.
*/
public class NetworkSecurityPolicy {
- private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();
+ private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();
- private boolean mCleartextTrafficPermitted = true;
+ private NetworkSecurityPolicy() {}
- private NetworkSecurityPolicy() {}
-
- /**
- * Gets the policy.
- */
- public static NetworkSecurityPolicy getInstance() {
- return INSTANCE;
- }
-
- /**
- * Checks whether cleartext network traffic (e.g., HTTP, WebSockets, XMPP, IMAP, SMTP -- without
- * TLS or STARTTLS) is permitted for this process.
- *
- * <p>When cleartext network traffic is not permitted, the platform's components (e.g., HTTP
- * stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use
- * cleartext traffic. Third-party libraries are encouraged to honor this setting as well.
- */
- public boolean isCleartextTrafficPermitted() {
- synchronized (this) {
- return mCleartextTrafficPermitted;
+ /**
+ * Gets the policy for this process.
+ *
+ * <p>It's fine to cache this reference. Any changes to the policy will be immediately visible
+ * through the reference.
+ */
+ public static NetworkSecurityPolicy getInstance() {
+ return INSTANCE;
}
- }
- /**
- * Sets whether cleartext network traffic is permitted for this process.
- *
- * <p>This method is used by the platform early on in the application's initialization to set the
- * policy.
- *
- * @hide
- */
- public void setCleartextTrafficPermitted(boolean permitted) {
- synchronized (this) {
- mCleartextTrafficPermitted = permitted;
+ /**
+ * Returns whether cleartext network traffic (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP --
+ * without TLS or STARTTLS) is permitted for this process.
+ *
+ * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and
+ * FTP stacks, {@link android.webkit.WebView}, {@link android.media.MediaPlayer}) will refuse
+ * this process's requests to use cleartext traffic. Third-party libraries are strongly
+ * encouraged to honor this setting as well.
+ *
+ * <p>This flag is honored on a best effort basis because it's impossible to prevent all
+ * cleartext traffic from Android applications given the level of access provided to them. For
+ * example, there's no expectation that the {@link java.net.Socket} API will honor this flag
+ * because it cannot determine whether its traffic is in cleartext. However, most network
+ * traffic from applications is handled by higher-level network stacks/components which can
+ * honor this aspect of the policy.
+ */
+ public boolean isCleartextTrafficPermitted() {
+ return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted();
}
- }
+
+ /**
+ * Sets whether cleartext network traffic is permitted for this process.
+ *
+ * <p>This method is used by the platform early on in the application's initialization to set
+ * the policy.
+ *
+ * @hide
+ */
+ public void setCleartextTrafficPermitted(boolean permitted) {
+ libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted);
+ }
}
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
new file mode 100644
index 0000000..8f70f7c
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, 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.security.keymaster;
+
+/* @hide */
+parcelable KeymasterBlob;
diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java
new file mode 100644
index 0000000..cb95604
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015, 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.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class KeymasterBlob implements Parcelable {
+ public byte[] blob;
+
+ public KeymasterBlob(byte[] blob) {
+ this.blob = blob;
+ }
+ public static final Parcelable.Creator<KeymasterBlob> CREATOR = new
+ Parcelable.Creator<KeymasterBlob>() {
+ public KeymasterBlob createFromParcel(Parcel in) {
+ return new KeymasterBlob(in);
+ }
+
+ public KeymasterBlob[] newArray(int length) {
+ return new KeymasterBlob[length];
+ }
+ };
+
+ protected KeymasterBlob(Parcel in) {
+ blob = in.createByteArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeByteArray(blob);
+ }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
index 9af4445..7d587bf 100644
--- a/core/java/android/security/keymaster/KeymasterBlobArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -26,6 +26,13 @@
public KeymasterBlobArgument(int tag, byte[] blob) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_BIGNUM:
+ case KeymasterDefs.KM_BYTES:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad blob tag " + tag);
+ }
this.blob = blob;
}
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
index 5481e8f..9c03674 100644
--- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -28,6 +28,12 @@
public KeymasterBooleanArgument(int tag) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_BOOL:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad bool tag " + tag);
+ }
}
public KeymasterBooleanArgument(int tag, Parcel in) {
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
index 310f546..bffd24d 100644
--- a/core/java/android/security/keymaster/KeymasterDateArgument.java
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -27,6 +27,12 @@
public KeymasterDateArgument(int tag, Date date) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_DATE:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad date tag " + tag);
+ }
this.date = date;
}
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
index c3738d7..da81715 100644
--- a/core/java/android/security/keymaster/KeymasterIntArgument.java
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -26,6 +26,15 @@
public KeymasterIntArgument(int tag, int value) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_INT:
+ case KeymasterDefs.KM_INT_REP:
+ case KeymasterDefs.KM_ENUM:
+ case KeymasterDefs.KM_ENUM_REP:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad int tag " + tag);
+ }
this.value = value;
}
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index 3c565b8..9d2be09 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -26,6 +26,12 @@
public KeymasterLongArgument(int tag, long value) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_LONG:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad long tag " + tag);
+ }
this.value = value;
}
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/service/fingerprint/Fingerprint.aidl
new file mode 100644
index 0000000..c9fd989
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+// @hide
+parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/service/fingerprint/Fingerprint.java
new file mode 100644
index 0000000..37552eb
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for fingerprint metadata.
+ * @hide
+ */
+public final class Fingerprint implements Parcelable {
+ private CharSequence mName;
+ private int mGroupId;
+ private int mFingerId;
+ private long mDeviceId; // physical device this is associated with
+
+ public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
+ mName = name;
+ mGroupId = groupId;
+ mFingerId = fingerId;
+ mDeviceId = deviceId;
+ }
+
+ private Fingerprint(Parcel in) {
+ mName = in.readString();
+ mGroupId = in.readInt();
+ mFingerId = in.readInt();
+ mDeviceId = in.readLong();
+ }
+
+ /**
+ * Gets the human-readable name for the given fingerprint.
+ * @return name given to finger
+ */
+ public CharSequence getName() { return mName; }
+
+ /**
+ * Gets the device-specific finger id. Used by Settings to map a name to a specific
+ * fingerprint template.
+ * @return device-specific id for this finger
+ * @hide
+ */
+ public int getFingerId() { return mFingerId; }
+
+ /**
+ * Gets the group id specified when the fingerprint was enrolled.
+ * @return group id for the set of fingerprints this one belongs to.
+ * @hide
+ */
+ public int getGroupId() { return mGroupId; }
+
+ /**
+ * Device this fingerprint belongs to.
+ * @hide
+ */
+ public long getDeviceId() { return mDeviceId; }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName.toString());
+ out.writeInt(mGroupId);
+ out.writeInt(mFingerId);
+ out.writeLong(mDeviceId);
+ }
+
+ public static final Parcelable.Creator<Fingerprint> CREATOR
+ = new Parcelable.Creator<Fingerprint>() {
+ public Fingerprint createFromParcel(Parcel in) {
+ return new Fingerprint(in);
+ }
+
+ public Fingerprint[] newArray(int size) {
+ return new Fingerprint[size];
+ }
+ };
+};
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 6375668..bb90e40 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -20,17 +20,25 @@
import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
import android.util.Log;
import android.util.Slog;
+import java.security.Signature;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import javax.crypto.Cipher;
+
/**
* A class that coordinates access to the fingerprint hardware.
* @hide
@@ -45,9 +53,6 @@
private static final int MSG_ERROR = 103;
private static final int MSG_REMOVED = 104;
- // Errors generated by layers above HAL
- public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
-
// Message types. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR = -1;
public static final int FINGERPRINT_ACQUIRED = 1;
@@ -60,52 +65,420 @@
public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+ public static final int FINGERPRINT_ERROR_CANCELED = 5;
+ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
- // FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h)
+ // Image acquisition messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
- public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
- public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
- public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
private IFingerprintService mService;
- private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
private IBinder mToken = new Binder();
+ private AuthenticationCallback mAuthenticationCallback;
+ private EnrollmentCallback mEnrollmentCallback;
+ private RemovalCallback mRemovalCallback;
+ private CryptoObject mCryptoObject;
+ private Fingerprint mRemovalFingerprint;
+ private boolean mListening;
+
+ /**
+ * A wrapper class for a limited number of crypto objects supported by FingerprintManager.
+ */
+ public static class CryptoObject {
+ CryptoObject(Signature signature) { mSignature = signature; }
+ CryptoObject(Cipher cipher) { mCipher = cipher; }
+ private Signature mSignature;
+ private Cipher mCipher;
+ };
+
+ /**
+ * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public static final class AuthenticationResult {
+ private Fingerprint mFingerprint;
+ private CryptoObject mCryptoObject;
+
+ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
+ mCryptoObject = crypto;
+ mFingerprint = fingerprint;
+ }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public CryptoObject getCryptoObject() { return mCryptoObject; }
+
+ /**
+ * Obtain the Fingerprint associated with this operation. Applications are discouraged
+ * from associating specific fingers with specific applications or operations. Hence this
+ * is not public.
+ * @hide
+ */
+ public Fingerprint getFingerprint() { return mFingerprint; }
+ };
+
+ /**
+ * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}. Users of {@link #FingerprintManager()}
+ * must provide an implementation of this to {@link FingerprintManager#authenticate(
+ * CryptoObject, AuthenticationCallback, CancellationSignal, int) for listening to fingerprint
+ * events.
+ */
+ public static abstract class AuthenticationCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ * @param errMsgId an integer identifying the error message.
+ * @param errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onAuthenticationError(int errMsgId, CharSequence errString);
+
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it."
+ * @param helpMsgId an integer identifying the error message.
+ * @param helpString a human-readible string that can be shown in UI.
+ */
+ public abstract void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
+
+ /**
+ * Called when a fingerprint is recognized.
+ * @param result an object containing authentication-related data.
+ */
+ public abstract void onAuthenticationSucceeded(AuthenticationResult result);
+ };
+
+ /**
+ * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
+ * CancellationSignal, int). Users of {@link #FingerprintManager()}
+ * must provide an implementation of this to {@link FingerprintManager#enroll(long,
+ * EnrollmentCallback, CancellationSignal, int) for listening to fingerprint events.
+ */
+ public static abstract class EnrollmentCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ * @param errMsgId an integer identifying the error message.
+ * @param errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onEnrollmentError(int errMsgId, CharSequence errString);
+
+ /**
+ * Called when a recoverable error has been encountered during enrollment. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it" or what they need to do next, such as
+ * "Touch sensor again."
+ * @param helpMsgId an integer identifying the error message.
+ * @param helpString a human-readible string that can be shown in UI.
+ */
+ public abstract void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
+
+ /**
+ * Called as each enrollment step progresses. Enrollment is considered complete when
+ * remaining reaches 0. This function will not be called if enrollment fails. See
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
+ * @param remaining the number of remaining steps.
+ */
+ public abstract void onEnrollmentProgress(int remaining);
+ };
+
+ /**
+ * Callback structure provided to {@link FingerprintManager#remove(int). Users of
+ * {@link #FingerprintManager()} may optionally provide an implementation of this to
+ * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
+ * fingerprint template removal events.
+ */
+ public static abstract class RemovalCallback {
+ /**
+ * Called when the given fingerprint can't be removed.
+ * @param fp the fingerprint that the call attempted to remove.
+ * @param errMsgId an associated error message id.
+ * @param errString an error message indicating why the fingerprint id can't be removed.
+ */
+ public abstract void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
+
+ /**
+ * Called when a given fingerprint is successfully removed.
+ * @param fingerprint the fingerprint template that was removed.
+ */
+ public abstract void onRemovalSucceeded(Fingerprint fingerprint);
+ };
+
+ /**
+ * Request authentication of a crypto object. This call warms up the fingerprint hardware
+ * and starts scanning for a fingerprint. It terminates when
+ * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ *
+ * @param crypto object associated with the call or null if none required.
+ * @param callback an object to receive authentication events
+ * @param cancel an object that can be used to cancel authentication
+ * @param flags optional flags
+ */
+ public void authenticate(CryptoObject crypto, AuthenticationCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an authentication callback");
+ }
+
+ // TODO: handle cancel
+
+ if (mService != null) try {
+ mAuthenticationCallback = callback;
+ mCryptoObject = crypto;
+ long sessionId = 0; // TODO: get from crypto object
+ startListening();
+ mService.authenticate(mToken, sessionId, getCurrentUserId(), flags);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while authenticating: ", e);
+ stopListening();
+ }
+ }
+
+ /**
+ * Request fingerprint enrollment. This call warms up the fingerprint hardware
+ * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
+ * {@link EnrollmentCallback} object. It terminates when
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
+ * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ * @param challenge a unique id provided by a recent verification of device credentials
+ * (e.g. pin, pattern or password).
+ * @param callback an object to receive enrollment events
+ * @param cancel an object that can be used to cancel enrollment
+ * @param flags optional flags
+ */
+ public void enroll(long challenge, EnrollmentCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an enrollment callback");
+ }
+
+ // TODO: handle cancel
+
+ if (mService != null) try {
+ mEnrollmentCallback = callback;
+ startListening();
+ mService.enroll(mToken, getCurrentUserId(), flags);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in enroll: ", e);
+ stopListening();
+ }
+ }
+
+ /**
+ * Remove given fingerprint template from fingerprint hardware and/or protected storage.
+ * @param fp the fingerprint item to remove
+ * @param callback an optional callback to verify that fingerprint templates have been
+ * successfully removed. May be null of no callback is required.
+ * @hide
+ */
+ public void remove(Fingerprint fp, RemovalCallback callback) {
+ if (mService != null) try {
+ mRemovalCallback = callback;
+ mRemovalFingerprint = fp;
+ startListening();
+ mService.remove(mToken, fp.getFingerId(), getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote in remove: ", e);
+ stopListening();
+ }
+ }
+
+ /**
+ * Renames the given fingerprint template
+ * @param fpId the fingerprint id
+ * @param newName the new name
+ * @hide
+ */
+ public void rename(int fpId, String newName) {
+ // Renames the given fpId
+ if (mService != null) {
+ try {
+ mService.rename(fpId, getCurrentUserId(), newName);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in rename(): ", e);
+ }
+ } else {
+ Log.w(TAG, "rename(): Service not connected!");
+ }
+ }
+
+ /**
+ * Obtain the list of enrolled fingerprints templates.
+ * @return list of current fingerprint items
+ */
+ public List<Fingerprint> getEnrolledFingerprints() {
+ if (mService != null) try {
+ return mService.getEnrolledFingerprints(getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ }
+ return null;
+ }
+
+ /**
+ * Determine if fingerprint hardware is present and functional.
+ * @return true if hardware is present and functional, false otherwise.
+ * @hide
+ */
+ public boolean isHardwareDetected() {
+ if (mService != null) {
+ try {
+ long deviceId = 0; /* TODO: plumb hardware id to FPMS */
+ return mService.isHardwareDetected(deviceId);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+ }
+ } else {
+ Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+ }
+ return false;
+ }
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
- if (mClientReceiver != null) {
- switch(msg.what) {
- case MSG_ENROLL_RESULT:
- mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
- break;
- case MSG_ACQUIRED:
- mClientReceiver.onAcquired(msg.arg1);
- break;
- case MSG_PROCESSED:
- mClientReceiver.onProcessed(msg.arg1);
- break;
- case MSG_ERROR:
- mClientReceiver.onError(msg.arg1);
- break;
- case MSG_REMOVED:
- mClientReceiver.onRemoved(msg.arg1);
+ switch(msg.what) {
+ case MSG_ENROLL_RESULT:
+ sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
+ break;
+ case MSG_ACQUIRED:
+ sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
+ break;
+ case MSG_PROCESSED:
+ sendProcessedResult((Fingerprint) msg.obj);
+ break;
+ case MSG_ERROR:
+ sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
+ break;
+ case MSG_REMOVED:
+ sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
+ msg.arg2 /* groupId */);
+ }
+ }
+
+ private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
+ if (mRemovalCallback != null) {
+ int reqFingerId = mRemovalFingerprint.getFingerId();
+ int reqGroupId = mRemovalFingerprint.getGroupId();
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
}
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ }
+ mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
+ }
+ }
+
+ private void sendErrorResult(long deviceId, int errMsgId) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
+ } else if (mRemovalCallback != null) {
+ mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
+ getErrorString(errMsgId));
+ }
+ }
+
+ private void sendEnrollResult(Fingerprint fp, int remaining) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentProgress(remaining);
+ }
+ }
+
+ private void sendProcessedResult(Fingerprint fp) {
+ if (mAuthenticationCallback != null) {
+ AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
+ mAuthenticationCallback.onAuthenticationSucceeded(result);
+ }
+ }
+
+ private void sendAcquiredResult(long deviceId, int acquireInfo) {
+ final String msg = getAcquiredString(acquireInfo);
+ if (msg == null) return;
+
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
+ }
+ }
+
+ private String getErrorString(int errMsg) {
+ switch (errMsg) {
+ case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_unable_to_process);
+ case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_hw_not_available);
+ case FINGERPRINT_ERROR_NO_SPACE:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_no_space);
+ case FINGERPRINT_ERROR_TIMEOUT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_timeout);
+ default:
+ if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
+ int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_error_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
+ }
+ }
+
+ private String getAcquiredString(int acquireInfo) {
+ switch (acquireInfo) {
+ case FINGERPRINT_ACQUIRED_GOOD:
+ return null;
+ case FINGERPRINT_ACQUIRED_PARTIAL:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_partial);
+ case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_insufficient);
+ case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_imager_dirty);
+ case FINGERPRINT_ACQUIRED_TOO_SLOW:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_too_slow);
+ case FINGERPRINT_ACQUIRED_TOO_FAST:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_too_fast);
+ default:
+ if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+ int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_acquired_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
}
}
};
- public static final class FingerprintItem {
- public CharSequence name;
- public int id;
- FingerprintItem(CharSequence name, int id) {
- this.name = name;
- this.id = id;
- }
- }
-
/**
* @hide
*/
@@ -117,99 +490,6 @@
}
}
- private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
-
- public void onEnrollResult(int fingerprintId, int remaining) {
- mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
- }
-
- public void onAcquired(int acquireInfo) {
- mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
- }
-
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
- }
-
- public void onError(int error) {
- mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
- }
-
- public void onRemoved(int fingerprintId) {
- mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
- }
- };
-
- /**
- * Determine whether the user has at least one fingerprint enrolled and enabled.
- *
- * @return true if at least one is enrolled and enabled
- */
- public boolean enrolledAndEnabled() {
- ContentResolver res = mContext.getContentResolver();
- return Settings.Secure.getInt(res, "fingerprint_enabled", 0) != 0
- && FingerprintUtils.getFingerprintIdsForUser(res, getCurrentUserId()).length > 0;
- }
-
- /**
- * Start the enrollment process. Timeout dictates how long to wait for the user to
- * enroll a fingerprint.
- *
- * @param timeout
- */
- public void enroll(long timeout) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
- }
- if (mService != null) try {
- mService.enroll(mToken, timeout, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception while enrolling: ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
- }
- }
-
- /**
- * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
- * which is to delete all fingerprint data for the current user. Use with caution.
- * @param fingerprintId
- */
- public void remove(int fingerprintId) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
- }
- if (mService != null) {
- try {
- mService.remove(mToken, fingerprintId, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
- }
- } else {
- Log.w(TAG, "remove(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
- }
- }
-
- /**
- * Starts listening for fingerprint events. When a finger is scanned or recognized, the
- * client will be notified via the callback.
- */
- public void startListening(FingerprintManagerReceiver receiver) {
- mClientReceiver = receiver;
- if (mService != null) {
- try {
- mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception in startListening(): ", e);
- }
- } else {
- Log.w(TAG, "startListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
- }
- }
-
private int getCurrentUserId() {
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
@@ -222,92 +502,62 @@
/**
* Stops the client from listening to fingerprint events.
*/
- public void stopListening() {
+ private void stopListening() {
if (mService != null) {
try {
- mService.stopListening(mToken, getCurrentUserId());
- mClientReceiver = null;
+ if (mListening) {
+ mService.removeListener(mToken, mServiceReceiver);
+ mListening = false;
+ }
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
Log.w(TAG, "stopListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
- public void enrollCancel() {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
- }
- if (mService != null) {
- try {
- mService.enrollCancel(mToken, getCurrentUserId());
- mClientReceiver = null;
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception in enrollCancel(): ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
- }
- } else {
- Log.w(TAG, "enrollCancel(): Service not connected!");
- }
- }
-
- private void sendError(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(msg, arg1, arg2);
- }
-
/**
- * @return list of current fingerprint items
- * @hide
+ * Starts listening for fingerprint events for this client.
*/
- public List<FingerprintItem> getEnrolledFingerprints() {
- int[] ids = FingerprintUtils.getFingerprintIdsForUser(mContext.getContentResolver(),
- getCurrentUserId());
- List<FingerprintItem> result = new ArrayList<FingerprintItem>();
- for (int i = 0; i < ids.length; i++) {
- // TODO: persist names in Settings
- FingerprintItem item = new FingerprintItem("Finger" + ids[i], ids[i]);
- result.add(item);
- }
- return result;
- }
-
- /**
- * Determine if fingerprint hardware is present and functional.
- * @return true if hardware is present and functional, false otherwise.
- * @hide
- */
- public boolean isHardwareDetected() {
+ private void startListening() {
if (mService != null) {
try {
- return mService.isHardwareDetected();
+ if (!mListening) {
+ mService.addListener(mToken, mServiceReceiver, getCurrentUserId());
+ mListening = true;
+ }
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+ Log.v(TAG, "Remote exception in startListening(): ", e);
}
} else {
- Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+ Log.w(TAG, "startListening(): Service not connected!");
}
- return false;
}
- /**
- * Renames the given fingerprint template
- * @param fpId the fingerprint id
- * @param newName the new name
- * @hide
- */
- public void rename(int fpId, String newName) {
- // Renames the given fpId
- if (mService != null) {
- try {
- mService.rename(fpId, newName);
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception in rename(): ", e);
- }
- } else {
- Log.w(TAG, "rename(): Service not connected!");
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
- }
+
+ public void onAcquired(long deviceId, int acquireInfo) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
+ }
+
+ public void onProcessed(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_PROCESSED,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+ }
+
+ public void onError(long deviceId, int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
+ }
+
+ public void onRemoved(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
+ }
+ };
+
}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
deleted file mode 100644
index 85677ba..0000000
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package android.service.fingerprint;
-/**
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @hide
- */
-public class FingerprintManagerReceiver {
- /**
- * Fingerprint enrollment progress update. Enrollment is considered complete if
- * remaining hits 0 without {@link #onError(int)} being called.
- *
- * @param fingerprintId the fingerprint we're currently enrolling
- * @param remaining the number of samples required to complete enrollment. It's up to
- * the hardware to define what each step in enrollment means. Some hardware
- * requires multiple samples of the same part of the finger. Others require sampling of
- * different parts of the finger. The enrollment flow can use remaining to
- * mean "step x" of the process or "just need another sample."
- */
- public void onEnrollResult(int fingerprintId, int remaining) { }
-
- /**
- * Fingerprint touch detected, but not processed yet. Clients will use this message to
- * determine a good or bad scan before the fingerprint is processed. This is meant for the
- * client to provide feedback about the scan or alert the user that recognition is to follow.
- *
- * @param acquiredInfo one of:
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
- */
- public void onAcquired(int acquiredInfo) { }
-
- /**
- * Fingerprint has been detected and processed. A non-zero return indicates a valid
- * fingerprint was detected.
- *
- * @param fingerprintId the finger id, or 0 if not recognized.
- */
- public void onProcessed(int fingerprintId) { }
-
- /**
- * An error was detected during scan or enrollment. One of
- * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
- * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
- * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
- * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
- *
- * @param error one of the above error codes
- */
- public void onError(int error) { }
-
- /**
- * The given fingerprint template was successfully removed by the driver.
- * See {@link FingerprintManager#remove(int)}
- *
- * @param fingerprintId id of template to remove.
- */
- public void onRemoved(int fingerprintId) { }
-}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index cc17b99..62acbb9 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -67,7 +67,7 @@
return toIntArray(tmp);
}
- public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ public static void addFingerprintIdForUser(ContentResolver res, int fingerId, int userId) {
// FingerId 0 has special meaning.
if (fingerId == 0) {
Log.w(TAG, "Tried to add fingerId 0");
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index 9b4750b..e5d3ad4 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -17,31 +17,42 @@
import android.os.Bundle;
import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.service.fingerprint.Fingerprint;
+import java.util.List;
/**
* Communication channel from client to the fingerprint service.
* @hide
*/
interface IFingerprintService {
- // Any errors resulting from this call will be returned to the listener
- void enroll(IBinder token, long timeout, int userId);
+ // Authenticate the given sessionId with a fingerprint
+ void authenticate(IBinder token, long sessionId, int groupId, int flags);
+
+ // Start fingerprint enrollment
+ void enroll(IBinder token, int groupId, int flags);
// Any errors resulting from this call will be returned to the listener
- void enrollCancel(IBinder token, int userId);
+ void remove(IBinder token, int fingerId, int groupId);
- // Any errors resulting from this call will be returned to the listener
- void remove(IBinder token, int fingerprintId, int userId);
+ // Rename the fingerprint specified by fingerId and groupId to the given name
+ void rename(int fingerId, int groupId, String name);
- // Start listening for fingerprint events. This has the side effect of starting
- // the hardware if not already started.
- void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+ // Get a list of enrolled fingerprints in the given group.
+ List<Fingerprint> getEnrolledFingerprints(int groupId);
- // Stops listening for fingerprints
- void stopListening(IBinder token, int userId);
+ // Register listener for an instance of FingerprintManager
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+
+ // Unregister listener for an instance of FingerprintManager
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected();
+ boolean isHardwareDetected(long deviceId);
- // Rename the given fingerprint id
- void rename(int fpId, String name);
+ // Gets the number of hardware devices
+ // int getHardwareDeviceCount();
+
+ // Gets the unique device id for hardware enumerated at i
+ // long getHardwareDevice(int i);
+
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index af4128f..f025064 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -23,9 +23,9 @@
* @hide
*/
oneway interface IFingerprintServiceReceiver {
- void onEnrollResult(int fingerprintId, int remaining);
- void onAcquired(int acquiredInfo);
- void onProcessed(int fingerprintId);
- void onError(int error);
- void onRemoved(int fingerprintId);
+ void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
+ void onAcquired(long deviceId, int acquiredInfo);
+ void onProcessed(long deviceId, int fingerId, int groupId);
+ void onError(long deviceId, int error);
+ void onRemoved(long deviceId, int fingerId, int groupId);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d46b6f5..1674950 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -155,7 +155,6 @@
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
int mCurWindowFlags = mWindowFlags;
int mCurWindowPrivateFlags = mWindowPrivateFlags;
- int mOutsetBottomPx;
final Rect mVisibleInsets = new Rect();
final Rect mWinFrame = new Rect();
final Rect mOverscanInsets = new Rect();
@@ -624,18 +623,9 @@
mLayout.token = mWindowToken;
if (!mCreated) {
- // Retrieve watch round and outset info
- final WindowManager windowService = (WindowManager)getSystemService(
- Context.WINDOW_SERVICE);
+ // Retrieve watch round info
TypedArray windowStyle = obtainStyledAttributes(
com.android.internal.R.styleable.Window);
- final Display display = windowService.getDefaultDisplay();
- final boolean shouldUseBottomOutset =
- display.getDisplayId() == Display.DEFAULT_DISPLAY;
- if (shouldUseBottomOutset) {
- mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx(
- getResources().getDisplayMetrics(), windowStyle);
- }
mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources());
windowStyle.recycle();
@@ -770,10 +760,7 @@
mDispatchedStableInsets.set(mStableInsets);
mFinalSystemInsets.set(mDispatchedOverscanInsets);
mFinalStableInsets.set(mDispatchedStableInsets);
- if (mOutsetBottomPx != 0) {
- mFinalSystemInsets.bottom =
- mIWallpaperEngine.mDisplayPadding.bottom + mOutsetBottomPx;
- }
+ mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom;
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
null, mFinalStableInsets, mWindowIsRound);
onApplyWindowInsets(insets);
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 8cf1b4b..7bebbfb 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -244,13 +244,18 @@
next++;
}
- withinParagraph(out, text, i, next - nl, nl, next == end);
+ if (withinParagraph(out, text, i, next - nl, nl, next == end)) {
+ /* Paragraph should be closed */
+ out.append("</p>\n");
+ out.append(getOpenParaTagWithDirection(text, next, end));
+ }
}
out.append("</p>\n");
}
- private static void withinParagraph(StringBuilder out, Spanned text,
+ /* Returns true if the caller should close and reopen the paragraph. */
+ private static boolean withinParagraph(StringBuilder out, Spanned text,
int start, int end, int nl,
boolean last) {
int next;
@@ -363,17 +368,14 @@
}
}
- String p = last ? "" : "</p>\n" + getOpenParaTagWithDirection(text, start, end);
-
if (nl == 1) {
out.append("<br>\n");
- } else if (nl == 2) {
- out.append(p);
+ return false;
} else {
for (int i = 2; i < nl; i++) {
out.append("<br>");
}
- out.append(p);
+ return !last;
}
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index fcf1828..928bf16 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1153,7 +1153,10 @@
return end - 1;
}
- if (ch != ' ' && ch != '\t') {
+ // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace()
+ if (!(ch == ' ' || ch == '\t' || ch == 0x1680 ||
+ (0x2000 <= ch && ch <= 0x200A && ch != 0x2007) ||
+ ch == 0x205F || ch == 0x3000)) {
break;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ee39e27..b47418f 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -170,8 +170,9 @@
* Measurement and break iteration is done in native code. The protocol for using
* the native code is as follows.
*
- * For each paragraph, do a nSetText of the paragraph text. Then, for each run within the
- * paragraph:
+ * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth.
+ *
+ * Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
* - one of the following, depending on the type of run:
* + addStyleRun (a text run, to be measured in native code)
@@ -459,7 +460,26 @@
byte[] chdirs = measured.mLevels;
int dir = measured.mDir;
boolean easy = measured.mEasy;
- nSetText(b.mNativePtr, chs, paraEnd - paraStart);
+
+ // tab stop locations
+ int[] variableTabStops = null;
+ if (spanned != null) {
+ TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ int[] stops = new int[spans.length];
+ for (int i = 0; i < spans.length; i++) {
+ stops[i] = spans[i].getTabStop();
+ }
+ Arrays.sort(stops, 0, stops.length);
+ variableTabStops = stops;
+ }
+ }
+
+ int breakStrategy = 0; // 0 = kBreakStrategy_Greedy
+ nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
+ firstWidth, firstWidthLineCount, restWidth,
+ variableTabStops, TAB_INCREMENT, breakStrategy);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -505,25 +525,9 @@
spanEndCacheCount++;
}
- // tab stop locations
- int[] variableTabStops = null;
- if (spanned != null) {
- TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
- paraEnd, TabStopSpan.class);
- if (spans.length > 0) {
- int[] stops = new int[spans.length];
- for (int i = 0; i < spans.length; i++) {
- stops[i] = spans[i].getTabStop();
- }
- Arrays.sort(stops, 0, stops.length);
- variableTabStops = stops;
- }
- }
-
nGetWidths(b.mNativePtr, widths);
- int breakCount = nComputeLineBreaks(b.mNativePtr, paraEnd - paraStart, firstWidth,
- firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
- lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
+ int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
+ lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
int[] breaks = lineBreaks.breaks;
float[] lineWidths = lineBreaks.widths;
@@ -966,7 +970,10 @@
private static native void nFinishBuilder(long nativePtr);
private static native void nSetLocale(long nativePtr, String locale);
- private static native void nSetText(long nativePtr, char[] text, int length);
+ // Set up paragraph text and settings; done as one big method to minimize jni crossings
+ private static native void nSetupParagraph(long nativePtr, char[] text, int length,
+ float firstWidth, int firstWidthLineCount, float restWidth,
+ int[] variableTabStops, int defaultTabStop, int breakStrategy);
private static native float nAddStyleRun(long nativePtr, long nativePaint,
long nativeTypeface, int start, int end, boolean isRtl);
@@ -983,9 +990,7 @@
// the arrays inside the LineBreaks objects are passed in as well
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
- private static native int nComputeLineBreaks(long nativePtr,
- int length, float firstWidth, int firstWidthLineCount, float restWidth,
- int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+ private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
private int mLineCount;
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index d29bfb6..0669b6f 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -23,6 +24,7 @@
import android.provider.Browser;
import android.text.ParcelableSpan;
import android.text.TextUtils;
+import android.util.Log;
import android.view.View;
public class URLSpan extends ClickableSpan implements ParcelableSpan {
@@ -59,6 +61,10 @@
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
- context.startActivity(intent);
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
+ }
}
}
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index e8d3947..9326203 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -18,6 +18,7 @@
import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
import libcore.util.EmptyArray;
/**
@@ -78,6 +79,24 @@
}
/**
+ * Searches the array for the specified value using the binary search algorithm. The array must
+ * be sorted (as by the {@link Arrays#sort(int[], int, int)} method) prior to making this call.
+ * If it is not sorted, the results are undefined. If the range contains multiple elements with
+ * the specified value, there is no guarantee which one will be found.
+ *
+ * @param value The value to search for.
+ * @return index of the search key, if it is contained in the array; otherwise, <i>(-(insertion
+ * point) - 1)</i>. The insertion point is defined as the point at which the key would
+ * be inserted into the array: the index of the first element greater than the key, or
+ * {@link #size()} if all elements in the array are less than the specified key.
+ * Note that this guarantees that the return value will be >= 0 if and only if the key
+ * is found.
+ */
+ public int binarySearch(int value) {
+ return ContainerHelpers.binarySearch(mValues, mSize, value);
+ }
+
+ /**
* Adds the values in the specified array to this array.
*/
public void addAll(IntArray values) {
@@ -159,4 +178,11 @@
public int size() {
return mSize;
}
+
+ /**
+ * Returns a new array with the contents of this IntArray.
+ */
+ public int[] toArray() {
+ return Arrays.copyOf(mValues, mSize);
+ }
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 59ec058..ad34f02 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -723,6 +723,12 @@
mSurface.release();
}
mSurface = surfaceTexture;
+
+ // If the view is visible, update the listener in the new surface to use
+ // the existing listener in the view.
+ if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) {
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
+ }
mUpdateSurface = true;
invalidateParentIfNeeded();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8538609..cfcc6fe 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -83,6 +83,7 @@
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -3195,9 +3196,9 @@
private static class ForegroundInfo {
private Drawable mDrawable;
private TintInfo mTintInfo;
- private int mGravity = Gravity.START | Gravity.TOP;
+ private int mGravity = Gravity.FILL;
private boolean mInsidePadding = true;
- private boolean mBoundsChanged;
+ private boolean mBoundsChanged = true;
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
}
@@ -5814,6 +5815,8 @@
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
}
+
+ info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
}
private View findLabelForView(View view, int labeledId) {
@@ -8261,6 +8264,13 @@
return true;
}
} break;
+ case R.id.accessibility_action_show_on_screen: {
+ if (mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ getDrawingRect(r);
+ return requestRectangleOnScreen(r, true);
+ }
+ } break;
}
return false;
}
@@ -16664,6 +16674,7 @@
}
mForegroundInfo.mDrawable = foreground;
+ mForegroundInfo.mBoundsChanged = true;
if (foreground != null) {
setWillNotDraw(false);
foreground.setCallback(this);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6096d7d..77082b0 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -29,6 +29,8 @@
import android.util.Pools.SynchronizedPool;
import android.view.View;
+import com.android.internal.R;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -3402,6 +3404,15 @@
new AccessibilityAction(
AccessibilityNodeInfo.ACTION_SET_TEXT, null);
+ /**
+ * Action that requests the node make its bounding rectangle visible
+ * on the screen, scrolling if necessary just enough.
+ *
+ * @see View#requestRectangleOnScreen(Rect)
+ */
+ public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
+ new AccessibilityAction(R.id.accessibility_action_show_on_screen, null);
+
private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
static {
sStandardActions.add(ACTION_FOCUS);
@@ -3426,6 +3437,7 @@
sStandardActions.add(ACTION_COLLAPSE);
sStandardActions.add(ACTION_DISMISS);
sStandardActions.add(ACTION_SET_TEXT);
+ sStandardActions.add(ACTION_SHOW_ON_SCREEN);
}
private final int mActionId;
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4737e9b..0b18bb8 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -284,13 +284,19 @@
* currently set for that origin. The host application should invoke the
* specified callback with the desired permission state. See
* {@link GeolocationPermissions} for details.
+ *
+ * If this method isn't overridden, the callback is invoked with permission
+ * denied state.
+ *
* @param origin The origin of the web content attempting to use the
* Geolocation API.
* @param callback The callback to use to set the permission state for the
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {}
+ GeolocationPermissions.Callback callback) {
+ callback.invoke(origin, false, false);
+ }
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 87fcd81..6e24837 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4664,8 +4664,8 @@
// Otherwise the user inserted the composition.
String newText = TextUtils.substring(source, start, end);
- EditOperation edit = new EditOperation(mEditor, false, "", dstart, newText);
- recordEdit(edit);
+ EditOperation edit = new EditOperation(mEditor, "", dstart, newText);
+ recordEdit(edit, false /* forceMerge */);
return true;
}
@@ -4684,11 +4684,15 @@
// Build a new operation with all the information from this edit.
String newText = TextUtils.substring(source, start, end);
String oldText = TextUtils.substring(dest, dstart, dend);
- EditOperation edit = new EditOperation(mEditor, forceMerge, oldText, dstart, newText);
- recordEdit(edit);
+ EditOperation edit = new EditOperation(mEditor, oldText, dstart, newText);
+ recordEdit(edit, forceMerge);
}
- private void recordEdit(EditOperation edit) {
+ /**
+ * Fetches the last undo operation and checks to see if a new edit should be merged into it.
+ * If forceMerge is true then the new edit is always merged.
+ */
+ private void recordEdit(EditOperation edit, boolean forceMerge) {
// Fetch the last edit operation and attempt to merge in the new edit.
final UndoManager um = mEditor.mUndoManager;
um.beginUpdate("Edit text");
@@ -4698,6 +4702,11 @@
// Add this as the first edit.
if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+ } else if (forceMerge) {
+ // Forced merges take priority because they could be the result of a non-user-edit
+ // change and this case should not create a new undo operation.
+ if (DEBUG_UNDO) Log.d(TAG, "filter: force merge " + edit);
+ lastEdit.forceMergeWith(edit);
} else if (!mIsUserEdit) {
// An application directly modified the Editable outside of a text edit. Treat this
// as a new change and don't attempt to merge.
@@ -4773,7 +4782,6 @@
private static final int TYPE_REPLACE = 2;
private int mType;
- private boolean mForceMerge;
private String mOldText;
private int mOldTextStart;
private String mNewText;
@@ -4784,13 +4792,10 @@
/**
* Constructs an edit operation from a text input operation on editor that replaces the
- * oldText starting at dstart with newText. If forceMerge is true then always forcibly
- * merge this operation with any previous one.
+ * oldText starting at dstart with newText.
*/
- public EditOperation(Editor editor, boolean forceMerge, String oldText, int dstart,
- String newText) {
+ public EditOperation(Editor editor, String oldText, int dstart, String newText) {
super(editor.mUndoOwner);
- mForceMerge = forceMerge;
mOldText = oldText;
mNewText = newText;
@@ -4817,7 +4822,6 @@
public EditOperation(Parcel src, ClassLoader loader) {
super(src, loader);
mType = src.readInt();
- mForceMerge = src.readInt() != 0;
mOldText = src.readString();
mOldTextStart = src.readInt();
mNewText = src.readString();
@@ -4829,7 +4833,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeInt(mForceMerge ? 1 : 0);
dest.writeString(mOldText);
dest.writeInt(mOldTextStart);
dest.writeString(mNewText);
@@ -4881,10 +4884,6 @@
Log.d(TAG, "mergeWith old " + this);
Log.d(TAG, "mergeWith new " + edit);
}
- if (edit.mForceMerge) {
- forceMergeWith(edit);
- return true;
- }
switch (mType) {
case TYPE_INSERT:
return mergeInsertWith(edit);
@@ -4942,7 +4941,7 @@
* Forcibly creates a single merged edit operation by simulating the entire text
* contents being replaced.
*/
- private void forceMergeWith(EditOperation edit) {
+ public void forceMergeWith(EditOperation edit) {
if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
Editor editor = getOwnerData();
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index af5a8bf..b187c1c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1209,13 +1209,13 @@
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
- if (movePrevious()) {
+ if (moveDirection(-1)) {
playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (moveNext()) {
+ if (moveDirection(1)) {
playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
return true;
}
@@ -1255,18 +1255,12 @@
return super.onKeyUp(keyCode, event);
}
- boolean movePrevious() {
- if (mItemCount > 0 && mSelectedPosition > 0) {
- scrollToChild(mSelectedPosition - mFirstPosition - 1);
- return true;
- } else {
- return false;
- }
- }
+ boolean moveDirection(int direction) {
+ direction = isLayoutRtl() ? -direction : direction;
+ int targetPosition = mSelectedPosition + direction;
- boolean moveNext() {
- if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
- scrollToChild(mSelectedPosition - mFirstPosition + 1);
+ if (mItemCount > 0 && targetPosition >= 0 && targetPosition < mItemCount) {
+ scrollToChild(targetPosition - mFirstPosition);
return true;
} else {
return false;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eaa0dc7..93dc995 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,18 +16,14 @@
package com.android.internal.os;
-import static android.net.NetworkStats.UID_ALL;
-import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
-import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiManager;
import android.os.BadParcelableException;
@@ -42,8 +38,6 @@
import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.WorkSource;
@@ -65,13 +59,14 @@
import android.util.Xml;
import android.view.Display;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.server.NetworkManagementSocketTagger;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -109,7 +104,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 121 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -132,6 +127,9 @@
static final int MSG_REPORT_POWER_CHANGE = 2;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
+ private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
+ private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
@@ -160,7 +158,12 @@
}
}
+ public interface ExternalStatsSync {
+ void scheduleSync();
+ }
+
public final MyHandler mHandler;
+ private final ExternalStatsSync mExternalSync;
private BatteryCallback mCallback;
@@ -330,7 +333,7 @@
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
- final StopwatchTimer[] mPhoneSignalStrengthsTimer =
+ final StopwatchTimer[] mPhoneSignalStrengthsTimer =
new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
StopwatchTimer mPhoneSignalScanningTimer;
@@ -445,18 +448,17 @@
private int mLoadedNumConnectivityChange;
private int mUnpluggedNumConnectivityChange;
+ private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
+
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
- private final HashMap<String, SamplingTimer> mKernelWakelockStats =
- new HashMap<String, SamplingTimer>();
+ private final HashMap<String, SamplingTimer> mKernelWakelockStats = new HashMap<>();
public Map<String, ? extends Timer> getKernelWakelockStats() {
return mKernelWakelockStats;
}
- private static int sKernelWakelockUpdateVersion = 0;
-
String mLastWakeupReason = null;
long mLastWakeupUptimeMs = 0;
private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
@@ -465,56 +467,12 @@
return mWakeupReasonStats;
}
- private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
- Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
- Process.PROC_QUOTES,
- Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime
- };
-
- private static final int[] WAKEUP_SOURCES_FORMAT = new int[] {
- Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
- Process.PROC_TAB_TERM|Process.PROC_COMBINE|
- Process.PROC_OUT_LONG, // 1: count
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE
- |Process.PROC_OUT_LONG, // 6: totalTime
- };
-
- private final String[] mProcWakelocksName = new String[3];
- private final long[] mProcWakelocksData = new long[3];
-
- /*
- * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
- * to mKernelWakelockStats.
- */
- private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
- new HashMap<String, KernelWakelockStats>();
-
- private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
- private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mLastMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mCurWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mLastWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mTmpNetworkStats;
- private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
-
- @GuardedBy("this")
- private String[] mMobileIfaces = new String[0];
- @GuardedBy("this")
- private String[] mWifiIfaces = new String[0];
-
public BatteryStatsImpl() {
mFile = null;
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
+ mExternalSync = null;
clearHistoryLocked();
}
@@ -524,7 +482,7 @@
}
static class TimeBase {
- private final ArrayList<TimeBaseObs> mObservers = new ArrayList<TimeBaseObs>();
+ private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
private long mUptime;
private long mRealtime;
@@ -1779,147 +1737,6 @@
return timer;
}
- private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
-
- FileInputStream is;
- byte[] buffer = new byte[32*1024];
- int len;
- boolean wakeup_sources;
-
- try {
- try {
- is = new FileInputStream("/d/wakeup_sources");
- wakeup_sources = true;
- } catch (java.io.FileNotFoundException e) {
- try {
- is = new FileInputStream("/proc/wakelocks");
- wakeup_sources = false;
- } catch (java.io.FileNotFoundException e2) {
- return null;
- }
- }
-
- len = is.read(buffer);
- is.close();
- } catch (java.io.IOException e) {
- return null;
- }
-
- if (len > 0) {
- if (len >= buffer.length) {
- Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
- }
- int i;
- for (i=0; i<len; i++) {
- if (buffer[i] == '\0') {
- len = i;
- break;
- }
- }
- }
-
- return parseProcWakelocks(buffer, len, wakeup_sources);
- }
-
- private final Map<String, KernelWakelockStats> parseProcWakelocks(
- byte[] wlBuffer, int len, boolean wakeup_sources) {
- String name;
- int count;
- long totalTime;
- int startIndex;
- int endIndex;
- int numUpdatedWlNames = 0;
-
- // Advance past the first line.
- int i;
- for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
- startIndex = endIndex = i + 1;
-
- synchronized(this) {
- Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
-
- sKernelWakelockUpdateVersion++;
- while (endIndex < len) {
- for (endIndex=startIndex;
- endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
- endIndex++);
- endIndex++; // endIndex is an exclusive upper bound.
- // Don't go over the end of the buffer, Process.parseProcLine might
- // write to wlBuffer[endIndex]
- if (endIndex >= (len - 1) ) {
- return m;
- }
-
- String[] nameStringArray = mProcWakelocksName;
- long[] wlData = mProcWakelocksData;
- // Stomp out any bad characters since this is from a circular buffer
- // A corruption is seen sometimes that results in the vm crashing
- // This should prevent crashes and the line will probably fail to parse
- for (int j = startIndex; j < endIndex; j++) {
- if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
- }
- boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
- wakeup_sources ? WAKEUP_SOURCES_FORMAT :
- PROC_WAKELOCKS_FORMAT,
- nameStringArray, wlData, null);
-
- name = nameStringArray[0];
- count = (int) wlData[1];
-
- if (wakeup_sources) {
- // convert milliseconds to microseconds
- totalTime = wlData[2] * 1000;
- } else {
- // convert nanoseconds to microseconds with rounding.
- totalTime = (wlData[2] + 500) / 1000;
- }
-
- if (parsed && name.length() > 0) {
- if (!m.containsKey(name)) {
- m.put(name, new KernelWakelockStats(count, totalTime,
- sKernelWakelockUpdateVersion));
- numUpdatedWlNames++;
- } else {
- KernelWakelockStats kwlStats = m.get(name);
- if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
- kwlStats.mCount += count;
- kwlStats.mTotalTime += totalTime;
- } else {
- kwlStats.mCount = count;
- kwlStats.mTotalTime = totalTime;
- kwlStats.mVersion = sKernelWakelockUpdateVersion;
- numUpdatedWlNames++;
- }
- }
- }
- startIndex = endIndex;
- }
-
- if (m.size() != numUpdatedWlNames) {
- // Don't report old data.
- Iterator<KernelWakelockStats> itr = m.values().iterator();
- while (itr.hasNext()) {
- if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
- itr.remove();
- }
- }
- }
- return m;
- }
- }
-
- private class KernelWakelockStats {
- public int mCount;
- public long mTotalTime;
- public int mVersion;
-
- KernelWakelockStats(int count, long totalTime, int version) {
- mCount = count;
- mTotalTime = totalTime;
- mVersion = version;
- }
- }
-
/*
* Get the KernelWakelockTimer associated with name, and create a new one if one
* doesn't already exist.
@@ -3391,7 +3208,7 @@
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
} else {
mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
- updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
+ updateMobileRadioStateLocked(realElapsedRealtimeMs);
mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
@@ -3729,6 +3546,7 @@
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = true;
mWifiOnTimer.startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -3742,6 +3560,7 @@
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -3904,6 +3723,7 @@
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
+ scheduleSyncExternalStatsLocked();
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
@@ -3942,6 +3762,7 @@
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
+ scheduleSyncExternalStatsLocked();
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
@@ -3956,6 +3777,7 @@
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -4027,6 +3849,7 @@
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = true;
mBluetoothOnTimer.startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -4040,6 +3863,7 @@
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = false;
mBluetoothOnTimer.stopRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -4066,6 +3890,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
mWifiFullLockNesting++;
getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
@@ -4081,6 +3906,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
}
@@ -4138,6 +3964,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
@@ -4153,6 +3980,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
}
@@ -4260,7 +4088,8 @@
// During device boot, qtaguid isn't enabled until after the inital
// loading of battery stats. Now that they're enabled, take our initial
// snapshot for future delta calculation.
- updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
+ updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
+ updateWifiStateLocked(null);
}
@Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
@@ -4607,17 +4436,17 @@
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
return mWakelockStats.getMap();
}
@Override
- public Map<String, ? extends BatteryStats.Timer> getSyncStats() {
+ public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
return mSyncStats.getMap();
}
@Override
- public Map<String, ? extends BatteryStats.Timer> getJobStats() {
+ public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() {
return mJobStats.getMap();
}
@@ -4627,12 +4456,12 @@
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
return mProcessStats;
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
return mPackageStats;
}
@@ -5950,7 +5779,7 @@
Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
return false;
}
-
+
mExcessivePower = new ArrayList<ExcessivePower>();
for (int i=0; i<N; i++) {
ExcessivePower ew = new ExcessivePower();
@@ -6153,40 +5982,20 @@
*/
public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
/**
- * Number of times this package has done something that could wake up the
- * device from sleep.
+ * Number of times wakeup alarms have occurred for this app.
*/
- int mWakeups;
-
- /**
- * Number of things that could wake up the device loaded from a
- * previous save.
- */
- int mLoadedWakeups;
-
- /**
- * Number of things that could wake up the device as of the
- * last run.
- */
- int mLastWakeups;
-
- /**
- * Number of things that could wake up the device as of the
- * last run.
- */
- int mUnpluggedWakeups;
+ ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>();
/**
* The statics we have collected for this package's services.
*/
- final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
+ final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
Pkg() {
mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedWakeups = mWakeups;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6197,10 +6006,12 @@
}
void readFromParcelLocked(Parcel in) {
- mWakeups = in.readInt();
- mLoadedWakeups = in.readInt();
- mLastWakeups = 0;
- mUnpluggedWakeups = in.readInt();
+ int numWA = in.readInt();
+ mWakeupAlarms.clear();
+ for (int i=0; i<numWA; i++) {
+ String tag = in.readString();
+ mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+ }
int numServs = in.readInt();
mServiceStats.clear();
@@ -6214,34 +6025,39 @@
}
void writeToParcelLocked(Parcel out) {
- out.writeInt(mWakeups);
- out.writeInt(mLoadedWakeups);
- out.writeInt(mUnpluggedWakeups);
+ int numWA = mWakeupAlarms.size();
+ out.writeInt(numWA);
+ for (int i=0; i<numWA; i++) {
+ out.writeString(mWakeupAlarms.keyAt(i));
+ mWakeupAlarms.valueAt(i).writeToParcel(out);
+ }
- out.writeInt(mServiceStats.size());
- for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
- out.writeString(servEntry.getKey());
- Uid.Pkg.Serv serv = servEntry.getValue();
-
+ final int NS = mServiceStats.size();
+ out.writeInt(NS);
+ for (int i=0; i<NS; i++) {
+ out.writeString(mServiceStats.keyAt(i));
+ Uid.Pkg.Serv serv = mServiceStats.valueAt(i);
serv.writeToParcelLocked(out);
}
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
- return mServiceStats;
+ public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() {
+ return mWakeupAlarms;
+ }
+
+ public void noteWakeupAlarmLocked(String tag) {
+ Counter c = mWakeupAlarms.get(tag);
+ if (c == null) {
+ c = new Counter(mOnBatteryTimeBase);
+ mWakeupAlarms.put(tag, c);
+ }
+ c.stepAtomic();
}
@Override
- public int getWakeups(int which) {
- int val = mWakeups;
- if (which == STATS_CURRENT) {
- val -= mLoadedWakeups;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedWakeups;
- }
-
- return val;
+ public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
+ return mServiceStats;
}
/**
@@ -6483,14 +6299,6 @@
}
}
- public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
- }
-
- public void incWakeupsLocked() {
- mWakeups++;
- }
-
final Serv newServiceStatsLocked() {
return new Serv();
}
@@ -6749,7 +6557,7 @@
}
}
- public BatteryStatsImpl(File systemDir, Handler handler) {
+ public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
@@ -6758,6 +6566,7 @@
}
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
+ mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6830,6 +6639,7 @@
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
+ mExternalSync = null;
clearHistoryLocked();
readFromParcel(p);
}
@@ -7501,21 +7311,233 @@
mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
}
}
-
+
public void pullPendingStateUpdatesLocked() {
- updateKernelWakelocksLocked();
- updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
- // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786
- // updateBluetoothControllerActivityLocked();
- // TODO(adamlesinski): disabled to avoid deadlock. Need to change how external
- // data is pulled/accessed from BatteryStats. b/19729960
- // updateWifiControllerActivityLocked();
if (mOnBatteryInternal) {
final boolean screenOn = mScreenState == Display.STATE_ON;
updateDischargeScreenLevelsLocked(screenOn, screenOn);
}
}
+ private String[] mMobileIfaces = EmptyArray.STRING;
+ private String[] mWifiIfaces = EmptyArray.STRING;
+
+ private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
+
+ private static final int NETWORK_STATS_LAST = 0;
+ private static final int NETWORK_STATS_NEXT = 1;
+ private static final int NETWORK_STATS_DELTA = 2;
+
+ private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50)
+ };
+
+ private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50)
+ };
+
+ /**
+ * Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
+ * as a buffer of NetworkStats objects to cycle through when computing deltas.
+ */
+ private NetworkStats getNetworkStatsDeltaLocked(String[] ifaces,
+ NetworkStats[] networkStatsBuffer)
+ throws IOException {
+ if (!SystemProperties.getBoolean(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
+ false)) {
+ return null;
+ }
+
+ final NetworkStats stats = mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL,
+ ifaces, NetworkStats.TAG_NONE, networkStatsBuffer[NETWORK_STATS_NEXT]);
+ networkStatsBuffer[NETWORK_STATS_DELTA] = NetworkStats.subtract(stats,
+ networkStatsBuffer[NETWORK_STATS_LAST], null, null,
+ networkStatsBuffer[NETWORK_STATS_DELTA]);
+ networkStatsBuffer[NETWORK_STATS_NEXT] = networkStatsBuffer[NETWORK_STATS_LAST];
+ networkStatsBuffer[NETWORK_STATS_LAST] = stats;
+ return networkStatsBuffer[NETWORK_STATS_DELTA];
+ }
+
+ /**
+ * Distribute WiFi energy info and network traffic to apps.
+ * @param info The energy information from the WiFi controller.
+ */
+ public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
+ final NetworkStats delta;
+ try {
+ delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed to get wifi network stats", e);
+ return;
+ }
+
+ if (!mOnBatteryInternal) {
+ return;
+ }
+
+ if (delta != null) {
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (DEBUG) {
+ Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ + " tx=" + entry.txBytes);
+ }
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) {
+ continue;
+ }
+
+ final Uid u = getUidStatsLocked(mapUid(entry.uid));
+ u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
+ entry.rxPackets);
+ u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
+ entry.txPackets);
+
+ mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxBytes);
+ mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txBytes);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxPackets);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txPackets);
+ }
+ }
+
+ if (info != null) {
+ // Update WiFi controller stats.
+ mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+ info.getControllerRxTimeMillis());
+ mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+ info.getControllerTxTimeMillis());
+ mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+ info.getControllerIdleTimeMillis());
+ mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+ info.getControllerEnergyUsed());
+ }
+ }
+
+ /**
+ * Distribute Cell radio energy info and network traffic to apps.
+ */
+ public void updateMobileRadioStateLocked(long elapsedRealtimeMs) {
+ final NetworkStats delta;
+
+ try {
+ delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed to get mobile network stats", e);
+ return;
+ }
+
+ if (delta == null || !mOnBatteryInternal) {
+ return;
+ }
+
+ long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(elapsedRealtimeMs);
+ long totalPackets = delta.getTotalPackets();
+
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+
+ final Uid u = getUidStatsLocked(mapUid(entry.uid));
+ u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
+ entry.rxPackets);
+ u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
+ entry.txPackets);
+
+ if (radioTime > 0) {
+ // Distribute total radio active time in to this app.
+ long appPackets = entry.rxPackets + entry.txPackets;
+ long appRadioTime = (radioTime*appPackets)/totalPackets;
+ u.noteMobileRadioActiveTimeLocked(appRadioTime);
+ // Remove this app from the totals, so that we don't lose any time
+ // due to rounding.
+ radioTime -= appRadioTime;
+ totalPackets -= appPackets;
+ }
+
+ mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+ entry.rxBytes);
+ mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+ entry.txBytes);
+ mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+ entry.rxPackets);
+ mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+ entry.txPackets);
+ }
+
+ if (radioTime > 0) {
+ // Whoops, there is some radio time we can't blame on an app!
+ mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+ mMobileRadioActiveUnknownCount.addCountLocked(1);
+ }
+ }
+
+ /**
+ * Distribute Bluetooth energy info and network traffic to apps.
+ * @param info The energy information from the bluetooth controller.
+ */
+ public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
+ if (info != null && mOnBatteryInternal) {
+ mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+ info.getControllerRxTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+ info.getControllerTxTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+ info.getControllerIdleTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+ info.getControllerEnergyUsed());
+ }
+ }
+
+ /**
+ * Read and distribute kernel wake lock use across apps.
+ */
+ public void updateKernelWakelocksLocked() {
+ final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
+ mTmpWakelockStats);
+ if (wakelockStats == null) {
+ // Not crashing might make board bringup easier.
+ Slog.w(TAG, "Couldn't get kernel wake lock stats");
+ return;
+ }
+
+ for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+ String name = ent.getKey();
+ KernelWakelockStats.Entry kws = ent.getValue();
+
+ SamplingTimer kwlt = mKernelWakelockStats.get(name);
+ if (kwlt == null) {
+ kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+ true /* track reported val */);
+ mKernelWakelockStats.put(name, kwlt);
+ }
+ kwlt.updateCurrentReportedCount(kws.mCount);
+ kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
+ kwlt.setUpdateVersion(kws.mVersion);
+ }
+
+ if (wakelockStats.size() != mKernelWakelockStats.size()) {
+ // Set timers to stale if they didn't appear in /proc/wakelocks this time.
+ for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+ SamplingTimer st = ent.getValue();
+ if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
+ st.setStale();
+ }
+ }
+ }
+ }
+
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
final int oldStatus, final int level) {
boolean doWrite = false;
@@ -7669,340 +7691,132 @@
}
}
+ private void scheduleSyncExternalStatsLocked() {
+ if (mExternalSync != null) {
+ mExternalSync.scheduleSync();
+ }
+ }
+
// This should probably be exposed in the API, though it's not critical
- private static final int BATTERY_PLUGGED_NONE = 0;
+ public static final int BATTERY_PLUGGED_NONE = 0;
- public void setBatteryState(int status, int health, int plugType, int level,
+ public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
- synchronized(this) {
- final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
- final long uptime = SystemClock.uptimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- if (!mHaveBatteryLevel) {
- mHaveBatteryLevel = true;
- // We start out assuming that the device is plugged in (not
- // on battery). If our first report is now that we are indeed
- // plugged in, then twiddle our state to correctly reflect that
- // since we won't be going through the full setOnBattery().
- if (onBattery == mOnBattery) {
- if (onBattery) {
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- } else {
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- }
- }
- mHistoryCur.batteryStatus = (byte)status;
- mHistoryCur.batteryLevel = (byte)level;
- mMaxChargeStepLevel = mMinDischargeStepLevel =
- mLastChargeStepLevel = mLastDischargeStepLevel = level;
- } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
- recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
- }
- int oldStatus = mHistoryCur.batteryStatus;
- if (onBattery) {
- mDischargeCurrentLevel = level;
- if (!mRecordingHistory) {
- mRecordingHistory = true;
- startRecordingHistory(elapsedRealtime, uptime, true);
- }
- } else if (level < 96) {
- if (!mRecordingHistory) {
- mRecordingHistory = true;
- startRecordingHistory(elapsedRealtime, uptime, true);
- }
- }
- mCurrentBatteryLevel = level;
- if (mDischargePlugLevel < 0) {
- mDischargePlugLevel = level;
- }
- if (onBattery != mOnBattery) {
- mHistoryCur.batteryLevel = (byte)level;
- mHistoryCur.batteryStatus = (byte)status;
- mHistoryCur.batteryHealth = (byte)health;
- mHistoryCur.batteryPlugType = (byte)plugType;
- mHistoryCur.batteryTemperature = (short)temp;
- mHistoryCur.batteryVoltage = (char)volt;
- setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
- } else {
- boolean changed = false;
- if (mHistoryCur.batteryLevel != level) {
- mHistoryCur.batteryLevel = (byte)level;
- changed = true;
- }
- if (mHistoryCur.batteryStatus != status) {
- mHistoryCur.batteryStatus = (byte)status;
- changed = true;
- }
- if (mHistoryCur.batteryHealth != health) {
- mHistoryCur.batteryHealth = (byte)health;
- changed = true;
- }
- if (mHistoryCur.batteryPlugType != plugType) {
- mHistoryCur.batteryPlugType = (byte)plugType;
- changed = true;
- }
- if (temp >= (mHistoryCur.batteryTemperature+10)
- || temp <= (mHistoryCur.batteryTemperature-10)) {
- mHistoryCur.batteryTemperature = (short)temp;
- changed = true;
- }
- if (volt > (mHistoryCur.batteryVoltage+20)
- || volt < (mHistoryCur.batteryVoltage-20)) {
- mHistoryCur.batteryVoltage = (char)volt;
- changed = true;
- }
- if (changed) {
- addHistoryRecordLocked(elapsedRealtime, uptime);
- }
- long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
- | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
- | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
+ final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
+ final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ if (!mHaveBatteryLevel) {
+ mHaveBatteryLevel = true;
+ // We start out assuming that the device is plugged in (not
+ // on battery). If our first report is now that we are indeed
+ // plugged in, then twiddle our state to correctly reflect that
+ // since we won't be going through the full setOnBattery().
+ if (onBattery == mOnBattery) {
if (onBattery) {
- if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
- mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
- modeBits, elapsedRealtime);
- mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
- modeBits, elapsedRealtime);
- mLastDischargeStepLevel = level;
- mMinDischargeStepLevel = level;
- mInitStepMode = mCurStepMode;
- mModStepMode = 0;
- }
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
} else {
- if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
- mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
- modeBits, elapsedRealtime);
- mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
- modeBits, elapsedRealtime);
- mLastChargeStepLevel = level;
- mMaxChargeStepLevel = level;
- mInitStepMode = mCurStepMode;
- mModStepMode = 0;
- }
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
- if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
- // We don't record history while we are plugged in and fully charged.
- // The next time we are unplugged, history will be cleared.
- mRecordingHistory = DEBUG;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryLevel = (byte)level;
+ mMaxChargeStepLevel = mMinDischargeStepLevel =
+ mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
+ recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
+ }
+ int oldStatus = mHistoryCur.batteryStatus;
+ if (onBattery) {
+ mDischargeCurrentLevel = level;
+ if (!mRecordingHistory) {
+ mRecordingHistory = true;
+ startRecordingHistory(elapsedRealtime, uptime, true);
+ }
+ } else if (level < 96) {
+ if (!mRecordingHistory) {
+ mRecordingHistory = true;
+ startRecordingHistory(elapsedRealtime, uptime, true);
}
}
- }
-
- public void updateKernelWakelocksLocked() {
- Map<String, KernelWakelockStats> m = readKernelWakelockStats();
-
- if (m == null) {
- // Not crashing might make board bringup easier.
- Slog.w(TAG, "Couldn't get kernel wake lock stats");
- return;
+ mCurrentBatteryLevel = level;
+ if (mDischargePlugLevel < 0) {
+ mDischargePlugLevel = level;
}
+ if (onBattery != mOnBattery) {
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryHealth = (byte)health;
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ mHistoryCur.batteryTemperature = (short)temp;
+ mHistoryCur.batteryVoltage = (char)volt;
+ setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
+ } else {
+ boolean changed = false;
+ if (mHistoryCur.batteryLevel != level) {
+ mHistoryCur.batteryLevel = (byte)level;
+ changed = true;
- for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
- String name = ent.getKey();
- KernelWakelockStats kws = ent.getValue();
-
- SamplingTimer kwlt = mKernelWakelockStats.get(name);
- if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
- true /* track reported val */);
- mKernelWakelockStats.put(name, kwlt);
+ // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
+ // which will pull external stats.
+ scheduleSyncExternalStatsLocked();
}
- kwlt.updateCurrentReportedCount(kws.mCount);
- kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
- kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
- }
-
- if (m.size() != mKernelWakelockStats.size()) {
- // Set timers to stale if they didn't appear in /proc/wakelocks this time.
- for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
- SamplingTimer st = ent.getValue();
- if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
- st.setStale();
+ if (mHistoryCur.batteryStatus != status) {
+ mHistoryCur.batteryStatus = (byte)status;
+ changed = true;
+ }
+ if (mHistoryCur.batteryHealth != health) {
+ mHistoryCur.batteryHealth = (byte)health;
+ changed = true;
+ }
+ if (mHistoryCur.batteryPlugType != plugType) {
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ changed = true;
+ }
+ if (temp >= (mHistoryCur.batteryTemperature+10)
+ || temp <= (mHistoryCur.batteryTemperature-10)) {
+ mHistoryCur.batteryTemperature = (short)temp;
+ changed = true;
+ }
+ if (volt > (mHistoryCur.batteryVoltage+20)
+ || volt < (mHistoryCur.batteryVoltage-20)) {
+ mHistoryCur.batteryVoltage = (char)volt;
+ changed = true;
+ }
+ if (changed) {
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
+ | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
+ | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
+ if (onBattery) {
+ if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
+ mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
+ mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
+ mLastDischargeStepLevel = level;
+ mMinDischargeStepLevel = level;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
+ }
+ } else {
+ if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
+ mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
+ mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
+ mLastChargeStepLevel = level;
+ mMaxChargeStepLevel = level;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
}
}
}
- }
-
- static final int NET_UPDATE_MOBILE = 1<<0;
- static final int NET_UPDATE_WIFI = 1<<1;
- static final int NET_UPDATE_ALL = 0xffff;
-
- private void updateNetworkActivityLocked(int which, long elapsedRealtimeMs) {
- if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
-
- if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) {
- final NetworkStats snapshot;
- final NetworkStats last = mCurMobileSnapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
- mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot);
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read mobile network stats", e);
- return;
- }
-
- mCurMobileSnapshot = snapshot;
- mLastMobileSnapshot = last;
-
- if (mOnBatteryInternal) {
- final NetworkStats delta = NetworkStats.subtract(snapshot, last,
- null, null, mTmpNetworkStats);
- mTmpNetworkStats = delta;
-
- long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(
- elapsedRealtimeMs);
- long totalPackets = delta.getTotalPackets();
-
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
-
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
-
- final Uid u = getUidStatsLocked(mapUid(entry.uid));
- u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
- entry.rxPackets);
- u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
- entry.txPackets);
-
- if (radioTime > 0) {
- // Distribute total radio active time in to this app.
- long appPackets = entry.rxPackets + entry.txPackets;
- long appRadioTime = (radioTime*appPackets)/totalPackets;
- u.noteMobileRadioActiveTimeLocked(appRadioTime);
- // Remove this app from the totals, so that we don't lose any time
- // due to rounding.
- radioTime -= appRadioTime;
- totalPackets -= appPackets;
- }
-
- mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
- entry.rxBytes);
- mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
- entry.txBytes);
- mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
- entry.rxPackets);
- mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
- entry.txPackets);
- }
-
- if (radioTime > 0) {
- // Whoops, there is some radio time we can't blame on an app!
- mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
- mMobileRadioActiveUnknownCount.addCountLocked(1);
- }
- }
+ if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
+ // We don't record history while we are plugged in and fully charged.
+ // The next time we are unplugged, history will be cleared.
+ mRecordingHistory = DEBUG;
}
-
- if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) {
- final NetworkStats snapshot;
- final NetworkStats last = mCurWifiSnapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
- mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot);
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read wifi network stats", e);
- return;
- }
-
- mCurWifiSnapshot = snapshot;
- mLastWifiSnapshot = last;
-
- if (mOnBatteryInternal) {
- final NetworkStats delta = NetworkStats.subtract(snapshot, last,
- null, null, mTmpNetworkStats);
- mTmpNetworkStats = delta;
-
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
-
- if (DEBUG) {
- final NetworkStats.Entry cur = snapshot.getValues(i, null);
- Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
- + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
- + " tx=" + cur.txBytes);
- }
-
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
-
- final Uid u = getUidStatsLocked(mapUid(entry.uid));
- u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
- entry.rxPackets);
- u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
- entry.txPackets);
-
- mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxBytes);
- mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txBytes);
- mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxPackets);
- mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txPackets);
- }
- }
- }
- }
-
- private void updateBluetoothControllerActivityLocked() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter == null) {
- return;
- }
-
- // We read the data even if we are not on battery. Each read clears
- // the previous data, so we must always read to make sure the
- // data is for the current interval.
- BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
- BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
- if (info == null || !info.isValid() || !mOnBatteryInternal) {
- // Bad info or we are not on battery.
- return;
- }
-
- mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
- info.getControllerRxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
- info.getControllerTxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
- info.getControllerIdleTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
- info.getControllerEnergyUsed());
- }
-
- private void updateWifiControllerActivityLocked() {
- IWifiManager wifiManager = IWifiManager.Stub.asInterface(
- ServiceManager.getService(Context.WIFI_SERVICE));
- if (wifiManager == null) {
- return;
- }
-
- WifiActivityEnergyInfo info;
- try {
- // We read the data even if we are not on battery. Each read clears
- // the previous data, so we must always read to make sure the
- // data is for the current interval.
- info = wifiManager.reportActivityInfo();
- } catch (RemoteException e) {
- // Nothing to report, WiFi is dead.
- return;
- }
-
- if (info == null || !info.isValid() || !mOnBatteryInternal) {
- // Bad info or we are not on battery.
- return;
- }
-
- mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
- info.getControllerRxTimeMillis());
- mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
- info.getControllerTxTimeMillis());
- mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
- info.getControllerIdleTimeMillis());
- mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
- info.getControllerEnergyUsed());
}
public long getAwakeTimeBattery() {
@@ -8938,7 +8752,18 @@
for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
- p.mWakeups = p.mLoadedWakeups = in.readInt();
+ final int NWA = in.readInt();
+ if (NWA > 1000) {
+ Slog.w(TAG, "File corrupt: too many wakeup alarms " + NWA);
+ return;
+ }
+ p.mWakeupAlarms.clear();
+ for (int iwa=0; iwa<NWA; iwa++) {
+ String tag = in.readString();
+ Counter c = new Counter(mOnBatteryTimeBase);
+ c.readSummaryFromParcelLocked(in);
+ p.mWakeupAlarms.put(tag, c);
+ }
NS = in.readInt();
if (NS > 1000) {
Slog.w(TAG, "File corrupt: too many services " + NS);
@@ -9263,20 +9088,22 @@
: u.mPackageStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Pkg ps = ent.getValue();
- out.writeInt(ps.mWakeups);
+ final int NWA = ps.mWakeupAlarms.size();
+ out.writeInt(NWA);
+ for (int iwa=0; iwa<NWA; iwa++) {
+ out.writeString(ps.mWakeupAlarms.keyAt(iwa));
+ ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
+ }
NS = ps.mServiceStats.size();
out.writeInt(NS);
- if (NS > 0) {
- for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
- : ps.mServiceStats.entrySet()) {
- out.writeString(sent.getKey());
- BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
- long time = ss.getStartTimeToNowLocked(
- mOnBatteryTimeBase.getUptime(NOW_SYS));
- out.writeLong(time);
- out.writeInt(ss.mStarts);
- out.writeInt(ss.mLaunches);
- }
+ for (int is=0; is<NS; is++) {
+ out.writeString(ps.mServiceStats.keyAt(is));
+ BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
+ long time = ss.getStartTimeToNowLocked(
+ mOnBatteryTimeBase.getUptime(NOW_SYS));
+ out.writeLong(time);
+ out.writeInt(ss.mStarts);
+ out.writeInt(ss.mLaunches);
}
}
}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
new file mode 100644
index 0000000..768d586
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.Process;
+import android.util.Slog;
+
+import java.io.FileInputStream;
+import java.util.Iterator;
+
+/**
+ * Reads and parses wakelock stats from the kernel (/proc/wakelocks).
+ */
+public class KernelWakelockReader {
+ private static final String TAG = "KernelWakelockReader";
+ private static int sKernelWakelockUpdateVersion = 0;
+ private static final String sWakelockFile = "/proc/wakelocks";
+ private static final String sWakeupSourceFile = "/d/wakeup_sources";
+
+ private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
+ Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
+ Process.PROC_QUOTES,
+ Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime
+ };
+
+ private static final int[] WAKEUP_SOURCES_FORMAT = new int[] {
+ Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE|
+ Process.PROC_OUT_LONG, // 1: count
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE
+ |Process.PROC_OUT_LONG, // 6: totalTime
+ };
+
+ private final String[] mProcWakelocksName = new String[3];
+ private final long[] mProcWakelocksData = new long[3];
+
+ /**
+ * Reads kernel wakelock stats and updates the staleStats with the new information.
+ * @param staleStats Existing object to update.
+ * @return the updated data.
+ */
+ public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
+ byte[] buffer = new byte[32*1024];
+ int len;
+ boolean wakeup_sources;
+
+ try {
+ FileInputStream is;
+ try {
+ is = new FileInputStream(sWakeupSourceFile);
+ wakeup_sources = true;
+ } catch (java.io.FileNotFoundException e) {
+ try {
+ is = new FileInputStream(sWakelockFile);
+ wakeup_sources = false;
+ } catch (java.io.FileNotFoundException e2) {
+ return null;
+ }
+ }
+
+ len = is.read(buffer);
+ is.close();
+ } catch (java.io.IOException e) {
+ return null;
+ }
+
+ if (len > 0) {
+ if (len >= buffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ }
+ int i;
+ for (i=0; i<len; i++) {
+ if (buffer[i] == '\0') {
+ len = i;
+ break;
+ }
+ }
+ }
+ return parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ }
+
+ /**
+ * Reads the wakelocks and updates the staleStats with the new information.
+ */
+ private KernelWakelockStats parseProcWakelocks(byte[] wlBuffer, int len, boolean wakeup_sources,
+ final KernelWakelockStats staleStats) {
+ String name;
+ int count;
+ long totalTime;
+ int startIndex;
+ int endIndex;
+ int numUpdatedWlNames = 0;
+
+ // Advance past the first line.
+ int i;
+ for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
+ startIndex = endIndex = i + 1;
+
+ synchronized(this) {
+ sKernelWakelockUpdateVersion++;
+ while (endIndex < len) {
+ for (endIndex=startIndex;
+ endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
+ endIndex++);
+ endIndex++; // endIndex is an exclusive upper bound.
+ // Don't go over the end of the buffer, Process.parseProcLine might
+ // write to wlBuffer[endIndex]
+ if (endIndex >= (len - 1) ) {
+ return staleStats;
+ }
+
+ String[] nameStringArray = mProcWakelocksName;
+ long[] wlData = mProcWakelocksData;
+ // Stomp out any bad characters since this is from a circular buffer
+ // A corruption is seen sometimes that results in the vm crashing
+ // This should prevent crashes and the line will probably fail to parse
+ for (int j = startIndex; j < endIndex; j++) {
+ if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
+ }
+ boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
+ wakeup_sources ? WAKEUP_SOURCES_FORMAT :
+ PROC_WAKELOCKS_FORMAT,
+ nameStringArray, wlData, null);
+
+ name = nameStringArray[0];
+ count = (int) wlData[1];
+
+ if (wakeup_sources) {
+ // convert milliseconds to microseconds
+ totalTime = wlData[2] * 1000;
+ } else {
+ // convert nanoseconds to microseconds with rounding.
+ totalTime = (wlData[2] + 500) / 1000;
+ }
+
+ if (parsed && name.length() > 0) {
+ if (!staleStats.containsKey(name)) {
+ staleStats.put(name, new KernelWakelockStats.Entry(count, totalTime,
+ sKernelWakelockUpdateVersion));
+ numUpdatedWlNames++;
+ } else {
+ KernelWakelockStats.Entry kwlStats = staleStats.get(name);
+ if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
+ kwlStats.mCount += count;
+ kwlStats.mTotalTime += totalTime;
+ } else {
+ kwlStats.mCount = count;
+ kwlStats.mTotalTime = totalTime;
+ kwlStats.mVersion = sKernelWakelockUpdateVersion;
+ numUpdatedWlNames++;
+ }
+ }
+ }
+ startIndex = endIndex;
+ }
+
+ if (staleStats.size() != numUpdatedWlNames) {
+ // Don't report old data.
+ Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
+ while (itr.hasNext()) {
+ if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
+ itr.remove();
+ }
+ }
+ }
+
+ staleStats.kernelWakelockVersion = sKernelWakelockUpdateVersion;
+ return staleStats;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelWakelockStats.java b/core/java/com/android/internal/os/KernelWakelockStats.java
new file mode 100644
index 0000000..144ea00
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelWakelockStats.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import java.util.HashMap;
+
+/**
+ * Kernel wakelock stats object.
+ */
+public class KernelWakelockStats extends HashMap<String, KernelWakelockStats.Entry> {
+ public static class Entry {
+ public int mCount;
+ public long mTotalTime;
+ public int mVersion;
+
+ Entry(int count, long totalTime, int version) {
+ mCount = count;
+ mTotalTime = totalTime;
+ mVersion = version;
+ }
+ }
+
+ int kernelWakelockVersion;
+}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index d9ebc25..a106f48 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -52,6 +52,7 @@
public static final int BASE_WIFI_RTT_SERVICE = 0x00027300;
public static final int BASE_WIFI_PASSPOINT_MANAGER = 0x00028000;
public static final int BASE_WIFI_PASSPOINT_SERVICE = 0x00028100;
+ public static final int BASE_WIFI_LOGGER = 0x00028300;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
new file mode 100644
index 0000000..be9945d
--- /dev/null
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+import com.android.internal.R;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A floating toolbar for showing contextual menu items.
+ * This view shows as many menu item buttons as can fit in the horizontal toolbar and the
+ * the remaining menu items in a vertical overflow view when the overflow button is clicked.
+ * The horizontal toolbar morphs into the vertical overflow view.
+ */
+public final class FloatingToolbar {
+
+ private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
+ new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ return false;
+ }
+ };
+
+ private final Context mContext;
+ private final FloatingToolbarPopup mPopup;
+ private final ViewGroup mMenuItemButtonsContainer;
+ private final View.OnClickListener mMenuItemButtonOnClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (v.getTag() instanceof MenuItem) {
+ mMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
+ mPopup.dismiss();
+ }
+ }
+ };
+
+ private final Rect mContentRect = new Rect();
+ private final Point mCoordinates = new Point();
+
+ private Menu mMenu;
+ private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>();
+ private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
+ private View mOpenOverflowButton;
+
+ private int mSuggestedWidth;
+
+ /**
+ * Initializes a floating toolbar.
+ */
+ public FloatingToolbar(Context context, Window window) {
+ mContext = Preconditions.checkNotNull(context);
+ mPopup = new FloatingToolbarPopup(Preconditions.checkNotNull(window.getDecorView()));
+ mMenuItemButtonsContainer = createMenuButtonsContainer(context);
+ }
+
+ /**
+ * Sets the menu to be shown in this floating toolbar.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setMenu(Menu menu) {
+ mMenu = Preconditions.checkNotNull(menu);
+ return this;
+ }
+
+ /**
+ * Sets the custom listener for invocation of menu items in this floating
+ * toolbar.
+ */
+ public FloatingToolbar setOnMenuItemClickListener(
+ MenuItem.OnMenuItemClickListener menuItemClickListener) {
+ if (menuItemClickListener != null) {
+ mMenuItemClickListener = menuItemClickListener;
+ } else {
+ mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the content rectangle. This is the area of the interesting content that this toolbar
+ * should avoid obstructing.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setContentRect(Rect rect) {
+ mContentRect.set(Preconditions.checkNotNull(rect));
+ return this;
+ }
+
+ /**
+ * Sets the suggested width of this floating toolbar.
+ * The actual width will be about this size but there are no guarantees that it will be exactly
+ * the suggested width.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
+ mSuggestedWidth = suggestedWidth;
+ return this;
+ }
+
+ /**
+ * Shows this floating toolbar.
+ */
+ public FloatingToolbar show() {
+ List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
+ if (hasContentChanged(menuItems) || hasWidthChanged()) {
+ mPopup.dismiss();
+ layoutMenuItemButtons(menuItems);
+ mShowingTitles = getMenuItemTitles(menuItems);
+ }
+ refreshCoordinates();
+ mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y);
+ if (!mPopup.isShowing()) {
+ mPopup.show(mCoordinates.x, mCoordinates.y);
+ }
+ return this;
+ }
+
+ /**
+ * Updates this floating toolbar to reflect recent position and view updates.
+ * NOTE: This method is a no-op if the toolbar isn't showing.
+ */
+ public FloatingToolbar updateLayout() {
+ if (mPopup.isShowing()) {
+ // show() performs all the logic we need here.
+ show();
+ }
+ return this;
+ }
+
+ /**
+ * Dismisses this floating toolbar.
+ */
+ public void dismiss() {
+ mPopup.dismiss();
+ }
+
+ /**
+ * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ */
+ public boolean isShowing() {
+ return mPopup.isShowing();
+ }
+
+ /**
+ * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
+ */
+ private void refreshCoordinates() {
+ int popupWidth = mPopup.getWidth();
+ int popupHeight = mPopup.getHeight();
+ if (!mPopup.isShowing()) {
+ // Popup isn't yet shown, get estimated size from the menu item buttons container.
+ mMenuItemButtonsContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ popupWidth = mMenuItemButtonsContainer.getMeasuredWidth();
+ popupHeight = mMenuItemButtonsContainer.getMeasuredHeight();
+ }
+ int x = mContentRect.centerX() - popupWidth / 2;
+ int y;
+ if (shouldDisplayAtTopOfContent()) {
+ y = mContentRect.top - popupHeight;
+ } else {
+ y = mContentRect.bottom;
+ }
+ mCoordinates.set(x, y);
+ }
+
+ /**
+ * Returns true if this floating toolbar's menu items have been reordered or changed.
+ */
+ private boolean hasContentChanged(List<MenuItem> menuItems) {
+ return !mShowingTitles.equals(getMenuItemTitles(menuItems));
+ }
+
+ /**
+ * Returns true if there is a significant change in width of the toolbar.
+ */
+ private boolean hasWidthChanged() {
+ int actualWidth = mPopup.getWidth();
+ int difference = Math.abs(actualWidth - mSuggestedWidth);
+ return difference > (actualWidth * 0.2);
+ }
+
+ /**
+ * Returns true if the preferred positioning of the toolbar is above the content rect.
+ */
+ private boolean shouldDisplayAtTopOfContent() {
+ return mContentRect.top - getMinimumOverflowHeight(mContext) > 0;
+ }
+
+ /**
+ * Returns the visible and enabled menu items in the specified menu.
+ * This method is recursive.
+ */
+ private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
+ List<MenuItem> menuItems = new ArrayList<MenuItem>();
+ for (int i = 0; (menu != null) && (i < menu.size()); i++) {
+ MenuItem menuItem = menu.getItem(i);
+ if (menuItem.isVisible() && menuItem.isEnabled()) {
+ Menu subMenu = menuItem.getSubMenu();
+ if (subMenu != null) {
+ menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu));
+ } else {
+ menuItems.add(menuItem);
+ }
+ }
+ }
+ return menuItems;
+ }
+
+ private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) {
+ List<CharSequence> titles = new ArrayList<CharSequence>();
+ for (MenuItem menuItem : menuItems) {
+ titles.add(menuItem.getTitle());
+ }
+ return titles;
+ }
+
+ private void layoutMenuItemButtons(List<MenuItem> menuItems) {
+ final int toolbarWidth = getAdjustedToolbarWidth(mContext, mSuggestedWidth)
+ // Reserve space for the "open overflow" button.
+ - getEstimatedOpenOverflowButtonWidth(mContext);
+
+ int availableWidth = toolbarWidth;
+ LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
+
+ mMenuItemButtonsContainer.removeAllViews();
+
+ boolean isFirstItem = true;
+ while (!remainingMenuItems.isEmpty()) {
+ final MenuItem menuItem = remainingMenuItems.peek();
+ Button menuItemButton = createMenuItemButton(mContext, menuItem);
+
+ // Adding additional left padding for the first button to even out button spacing.
+ if (isFirstItem) {
+ menuItemButton.setPadding(
+ 2 * menuItemButton.getPaddingLeft(),
+ menuItemButton.getPaddingTop(),
+ menuItemButton.getPaddingRight(),
+ menuItemButton.getPaddingBottom());
+ isFirstItem = false;
+ }
+
+ // Adding additional right padding for the last button to even out button spacing.
+ if (remainingMenuItems.size() == 1) {
+ menuItemButton.setPadding(
+ menuItemButton.getPaddingLeft(),
+ menuItemButton.getPaddingTop(),
+ 2 * menuItemButton.getPaddingRight(),
+ menuItemButton.getPaddingBottom());
+ }
+
+ menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+ if (menuItemButtonWidth <= availableWidth) {
+ menuItemButton.setTag(menuItem);
+ menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
+ mMenuItemButtonsContainer.addView(menuItemButton);
+ menuItemButton.getLayoutParams().width = menuItemButtonWidth;
+ availableWidth -= menuItemButtonWidth;
+ remainingMenuItems.pop();
+ } else {
+ // The "open overflow" button launches the vertical overflow from the
+ // floating toolbar.
+ createOpenOverflowButtonIfNotExists();
+ mMenuItemButtonsContainer.addView(mOpenOverflowButton);
+ break;
+ }
+ }
+ mPopup.setContentView(mMenuItemButtonsContainer);
+ }
+
+ /**
+ * Creates and returns the button that opens the vertical overflow.
+ */
+ private void createOpenOverflowButtonIfNotExists() {
+ mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
+ .inflate(R.layout.floating_popup_open_overflow_button, null);
+ mOpenOverflowButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Open the overflow.
+ }
+ });
+ }
+
+ /**
+ * Creates and returns a floating toolbar menu buttons container.
+ */
+ private static ViewGroup createMenuButtonsContainer(Context context) {
+ return (ViewGroup) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_container, null);
+ }
+
+ /**
+ * Creates and returns a menu button for the specified menu item.
+ */
+ private static Button createMenuItemButton(Context context, MenuItem menuItem) {
+ Button menuItemButton = (Button) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_menu_button, null);
+ menuItemButton.setText(menuItem.getTitle());
+ menuItemButton.setContentDescription(menuItem.getTitle());
+ return menuItemButton;
+ }
+
+ private static int getMinimumOverflowHeight(Context context) {
+ return context.getResources().
+ getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
+ }
+
+ private static int getEstimatedOpenOverflowButtonWidth(Context context) {
+ return context.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
+ }
+
+ private static int getAdjustedToolbarWidth(Context context, int width) {
+ if (width <= 0 || width > getScreenWidth(context)) {
+ width = context.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_default_width);
+ }
+ return width;
+ }
+
+ /**
+ * Returns the device's screen width.
+ */
+ public static int getScreenWidth(Context context) {
+ return context.getResources().getDisplayMetrics().widthPixels;
+ }
+
+ /**
+ * Returns the device's screen height.
+ */
+ public static int getScreenHeight(Context context) {
+ return context.getResources().getDisplayMetrics().heightPixels;
+ }
+
+
+ /**
+ * A popup window used by the floating toolbar.
+ */
+ private static final class FloatingToolbarPopup {
+
+ private final View mParent;
+ private final PopupWindow mPopupWindow;
+ private final ViewGroup mContentContainer;
+ private final Animator.AnimatorListener mOnDismissEnd =
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPopupWindow.dismiss();
+ mDismissAnimating = false;
+ }
+ };
+ private final AnimatorSet mGrowFadeInFromBottomAnimation;
+ private final AnimatorSet mShrinkFadeOutFromBottomAnimation;
+
+ private boolean mDismissAnimating;
+
+ /**
+ * Initializes a new floating bar popup.
+ *
+ * @param parent A parent view to get the {@link View#getWindowToken()} token from.
+ */
+ public FloatingToolbarPopup(View parent) {
+ mParent = Preconditions.checkNotNull(parent);
+ mContentContainer = createContentContainer(parent.getContext());
+ mPopupWindow = createPopupWindow(mContentContainer);
+ mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer);
+ mShrinkFadeOutFromBottomAnimation =
+ createShrinkFadeOutFromBottomAnimation(mContentContainer, mOnDismissEnd);
+ }
+
+ /**
+ * Shows this popup at the specified coordinates.
+ * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ * If this popup is already showing, this will be a no-op.
+ */
+ public void show(int x, int y) {
+ if (isShowing()) {
+ updateCoordinates(x, y);
+ return;
+ }
+
+ mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, 0, 0);
+ positionOnScreen(x, y);
+ growFadeInFromBottom();
+
+ mDismissAnimating = false;
+ }
+
+ /**
+ * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
+ */
+ public void dismiss() {
+ if (!isShowing()) {
+ return;
+ }
+
+ if (mDismissAnimating) {
+ // This window is already dismissing. Don't restart the animation.
+ return;
+ }
+ mDismissAnimating = true;
+ shrinkFadeOutFromBottom();
+ }
+
+ /**
+ * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ */
+ public boolean isShowing() {
+ return mPopupWindow.isShowing() && !mDismissAnimating;
+ }
+
+ /**
+ * Updates the coordinates of this popup.
+ * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ */
+ public void updateCoordinates(int x, int y) {
+ if (isShowing()) {
+ positionOnScreen(x, y);
+ }
+ }
+
+ /**
+ * Sets the content of this popup.
+ */
+ public void setContentView(View view) {
+ Preconditions.checkNotNull(view);
+ mContentContainer.removeAllViews();
+ mContentContainer.addView(view);
+ }
+
+ /**
+ * Returns the width of this popup.
+ */
+ public int getWidth() {
+ return mContentContainer.getWidth();
+ }
+
+ /**
+ * Returns the height of this popup.
+ */
+ public int getHeight() {
+ return mContentContainer.getHeight();
+ }
+
+ /**
+ * Returns the context this popup is running in.
+ */
+ public Context getContext() {
+ return mContentContainer.getContext();
+ }
+
+ private void positionOnScreen(int x, int y) {
+ if (getWidth() == 0) {
+ // content size is yet to be measured.
+ mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ }
+ x = clamp(x, 0, getScreenWidth(getContext()) - getWidth());
+ y = clamp(y, 0, getScreenHeight(getContext()) - getHeight());
+
+ // Position the view w.r.t. the window.
+ mContentContainer.setX(x);
+ mContentContainer.setY(y);
+ }
+
+ /**
+ * Performs the "grow and fade in from the bottom" animation on the floating popup.
+ */
+ private void growFadeInFromBottom() {
+ setPivot();
+ mGrowFadeInFromBottomAnimation.start();
+ }
+
+ /**
+ * Performs the "shrink and fade out from bottom" animation on the floating popup.
+ */
+ private void shrinkFadeOutFromBottom() {
+ setPivot();
+ mShrinkFadeOutFromBottomAnimation.start();
+ }
+
+ /**
+ * Sets the popup content container's pivot.
+ */
+ private void setPivot() {
+ mContentContainer.setPivotX(mContentContainer.getMeasuredWidth() / 2);
+ mContentContainer.setPivotY(mContentContainer.getMeasuredHeight());
+ }
+
+ private static ViewGroup createContentContainer(Context context) {
+ return (ViewGroup) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_container, null);
+ }
+
+ private static PopupWindow createPopupWindow(View content) {
+ ViewGroup popupContentHolder = new LinearLayout(content.getContext());
+ PopupWindow popupWindow = new PopupWindow(popupContentHolder);
+ popupWindow.setAnimationStyle(0);
+ popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ popupWindow.setWidth(getScreenWidth(content.getContext()));
+ popupWindow.setHeight(getScreenHeight(content.getContext()));
+ content.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ popupContentHolder.addView(content);
+ return popupWindow;
+ }
+
+ /**
+ * Creates a "grow and fade in from the bottom" animation for the specified view.
+ *
+ * @param view The view to animate
+ */
+ private static AnimatorSet createGrowFadeInFromBottom(View view) {
+ AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet();
+ growFadeInFromBottomAnimation.playTogether(
+ ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75));
+ return growFadeInFromBottomAnimation;
+ }
+
+ /**
+ * Creates a "shrink and fade out from bottom" animation for the specified view.
+ *
+ * @param view The view to animate
+ * @param listener The animation listener
+ */
+ private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
+ View view, Animator.AnimatorListener listener) {
+ AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet();
+ shrinkFadeOutFromBottomAnimation.playTogether(
+ ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
+ shrinkFadeOutFromBottomAnimation.setStartDelay(150);
+ shrinkFadeOutFromBottomAnimation.addListener(listener);
+ return shrinkFadeOutFromBottomAnimation;
+ }
+
+ /**
+ * Returns value, restricted to the range min->max (inclusive).
+ * If maximum is less than minimum, the result is undefined.
+ *
+ * @param value The value to clamp.
+ * @param minimum The minimum value in the range.
+ * @param maximum The maximum value in the range. Must not be less than minimum.
+ */
+ private static int clamp(int value, int minimum, int maximum) {
+ return Math.max(minimum, Math.min(value, maximum));
+ }
+ }
+}
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index 8139c24..8bdbff4 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -26,10 +26,10 @@
namespace android {
-void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
- const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
- TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
- layout->setFontCollection(resolvedFace->fFontCollection);
+FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+ const Paint* paint, TypefaceImpl* typeface) {
+ const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
+ *pFont = resolvedFace->fFontCollection;
FontStyle resolved = resolvedFace->fStyle;
/* Prepare minikin FontStyle */
@@ -40,15 +40,26 @@
FontStyle minikinStyle(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic());
/* Prepare minikin Paint */
- MinikinPaint minikinPaint;
- minikinPaint.size = (int)/*WHY?!*/paint->getTextSize();
- minikinPaint.scaleX = paint->getTextScaleX();
- minikinPaint.skewX = paint->getTextSkewX();
- minikinPaint.letterSpacing = paint->getLetterSpacing();
- minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
- minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
- minikinPaint.hyphenEdit = HyphenEdit(paint->getHyphenEdit());
+ // Note: it would be nice to handle fractional size values (it would improve smooth zoom
+ // behavior), but historically size has been treated as an int.
+ // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
+ minikinPaint->size = (int)paint->getTextSize();
+ minikinPaint->scaleX = paint->getTextScaleX();
+ minikinPaint->skewX = paint->getTextSkewX();
+ minikinPaint->letterSpacing = paint->getLetterSpacing();
+ minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
+ minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
+ minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit());
+ return minikinStyle;
+}
+void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+ TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
+ size_t bufSize) {
+ FontCollection *font;
+ MinikinPaint minikinPaint;
+ FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+ layout->setFontCollection(font);
layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
}
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 236f1fd..1ee6245 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -31,22 +31,14 @@
namespace android {
-// TODO: these should be defined in Minikin's Layout.h
-enum {
- kBidi_LTR = 0,
- kBidi_RTL = 1,
- kBidi_Default_LTR = 2,
- kBidi_Default_RTL = 3,
- kBidi_Force_LTR = 4,
- kBidi_Force_RTL = 5,
-
- kBidi_Mask = 0x7
-};
-
class MinikinUtils {
public:
- static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
- const uint16_t* buf, size_t start, size_t count, size_t bufSize);
+ static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+ const Paint* paint, TypefaceImpl* typeface);
+
+ static void doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+ TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
+ size_t bufSize);
static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index d36f83a..4b14917 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -62,4 +62,4 @@
}
-#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
\ No newline at end of file
+#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 0b737a7..7d12230 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -18,6 +18,8 @@
#include <map>
+#include <ScopedUtfChars.h>
+
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -99,6 +101,9 @@
if (string1 == NULL) {
return string2 != NULL;
}
+ if (string2 == NULL) {
+ return false;
+ }
return string1->compare(*string2) < 0;
}
};
@@ -264,9 +269,12 @@
}
};
-static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
+static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ,
+ jfloatArray scratch, jstring packageName) {
SensorManager& mgr(SensorManager::getInstance());
- sp<SensorEventQueue> queue(mgr.createEventQueue());
+ ScopedUtfChars packageUtf(env, packageName);
+ String8 clientName(packageUtf.c_str());
+ sp<SensorEventQueue> queue(mgr.createEventQueue(clientName));
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
@@ -280,10 +288,11 @@
}
static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
- jint maxBatchReportLatency, jint reservedFlags) {
+ jint maxBatchReportLatency) {
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
+
return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
- reservedFlags);
+ 0);
}
static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
@@ -316,11 +325,11 @@
static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
- "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
- (void*)nativeInitSensorEventQueue },
+ "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[FLjava/lang/String;)J",
+ (void*)nativeInitSensorEventQueue },
{"nativeEnableSensor",
- "(JIIII)I",
+ "(JIII)I",
(void*)nativeEnableSensor },
{"nativeDisableSensor",
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index 853425c..5d59234 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "Fingerprint-JNI"
#include "JNIHelp.h"
+#include <inttypes.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
@@ -47,14 +48,15 @@
class CallbackHandler : public MessageHandler {
int type;
- int arg1, arg2;
+ int arg1, arg2, arg3;
public:
- CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { }
+ CallbackHandler(int type, int arg1, int arg2, int arg3)
+ : type(type), arg1(arg1), arg2(arg2), arg3(arg3) { }
virtual void handleMessage(const Message& message) {
//ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2);
+ env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2, arg3);
}
};
@@ -62,6 +64,7 @@
static void hal_notify_callback(fingerprint_msg_t msg) {
uint32_t arg1 = 0;
uint32_t arg2 = 0;
+ uint32_t arg3 = 0;
switch (msg.type) {
case FINGERPRINT_ERROR:
arg1 = msg.data.error;
@@ -71,13 +74,16 @@
break;
case FINGERPRINT_PROCESSED:
arg1 = msg.data.processed.finger.fid;
+ arg2 = msg.data.processed.finger.gid;
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
arg1 = msg.data.enroll.finger.fid;
- arg2 = msg.data.enroll.samples_remaining;
+ arg2 = msg.data.enroll.finger.gid;
+ arg3 = msg.data.enroll.samples_remaining;
break;
case FINGERPRINT_TEMPLATE_REMOVED:
arg1 = msg.data.removed.finger.fid;
+ arg2 = msg.data.removed.finger.gid;
break;
default:
ALOGE("fingerprint: invalid msg: %d", msg.type);
@@ -86,7 +92,7 @@
// This call potentially comes in on a thread not owned by us. Hand it off to our
// looper so it runs on our thread when calling back to FingerprintService.
// CallbackHandler object is reference-counted, so no cleanup necessary.
- gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message());
+ gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2, arg3), Message());
}
static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) {
@@ -95,9 +101,15 @@
gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
}
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
- int ret = gContext.device->enroll(gContext.device, 0, timeout);
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout);
+ int ret = gContext.device->enroll(gContext.device, groupId, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeAuthenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
+ int ret = gContext.device->authenticate(gContext.device, sessionId, groupId);
return reinterpret_cast<jint>(ret);
}
@@ -107,11 +119,11 @@
return reinterpret_cast<jint>(ret);
}
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(fid=%d, gid=%d)\n", fingerId, groupId);
fingerprint_finger_id_t finger;
- finger.gid = 0;
- finger.fid = fingerprintId;
+ finger.fid = fingerId;
+ finger.gid = groupId;
int ret = gContext.device->remove(gContext.device, finger);
return reinterpret_cast<jint>(ret);
}
@@ -172,9 +184,10 @@
// TODO: clean up void methods
static const JNINativeMethod g_methods[] = {
- { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate },
+ { "nativeEnroll", "(II)I", (void*)nativeEnroll },
{ "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel },
- { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeRemove", "(II)I", (void*)nativeRemove },
{ "nativeOpenHal", "()I", (void*)nativeOpenHal },
{ "nativeCloseHal", "()I", (void*)nativeCloseHal },
{ "nativeInit","(Landroid/os/MessageQueue;"
@@ -185,7 +198,7 @@
jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE);
gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gFingerprintServiceClassInfo.notify =
- GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V");
+ GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(IIII)V");
int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
return result;
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 8800f0b..6cc1f68 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -34,6 +34,7 @@
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#include "Paint.h"
+#include "minikin/LineBreaker.h"
namespace android {
@@ -46,636 +47,116 @@
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
-class Builder {
- public:
- ~Builder() {
- utext_close(&mUText);
- delete mBreakIterator;
- }
-
- void setLocale(const icu::Locale& locale) {
- delete mBreakIterator;
- UErrorCode status = U_ZERO_ERROR;
- mBreakIterator = icu::BreakIterator::createLineInstance(locale, status);
- // TODO: check status
- }
-
- void resize(size_t size) {
- mTextBuf.resize(size);
- mWidthBuf.resize(size);
- }
-
- size_t size() const {
- return mTextBuf.size();
- }
-
- uint16_t* buffer() {
- return mTextBuf.data();
- }
-
- float* widths() {
- return mWidthBuf.data();
- }
-
- // set text to current contents of buffer
- void setText() {
- UErrorCode status = U_ZERO_ERROR;
- utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
- mBreakIterator->setText(&mUText, status);
- }
-
- void finish() {
- if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
- mTextBuf.clear();
- mTextBuf.shrink_to_fit();
- mWidthBuf.clear();
- mWidthBuf.shrink_to_fit();
- }
- }
-
- icu::BreakIterator* breakIterator() const {
- return mBreakIterator;
- }
-
- float measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
- bool isRtl);
-
- void addReplacement(size_t start, size_t end, float width);
-
- private:
- const size_t MAX_TEXT_BUF_RETAIN = 32678;
- icu::BreakIterator* mBreakIterator = nullptr;
- UText mUText = UTEXT_INITIALIZER;
- std::vector<uint16_t>mTextBuf;
- std::vector<float>mWidthBuf;
-};
-
static const int CHAR_SPACE = 0x20;
static const int CHAR_TAB = 0x09;
static const int CHAR_NEWLINE = 0x0a;
static const int CHAR_ZWSP = 0x200b;
-class TabStops {
- public:
- // specified stops must be a sorted array (allowed to be null)
- TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
- mStops(env), mTabWidth(defaultTabWidth) {
- if (stops != nullptr) {
- mStops.reset(stops);
- mNumStops = mStops.size();
- } else {
- mNumStops = 0;
- }
- }
- float width(float widthSoFar) const {
- const jint* mStopsArray = mStops.get();
- for (int i = 0; i < mNumStops; i++) {
- if (mStopsArray[i] > widthSoFar) {
- return mStopsArray[i];
- }
- }
- // find the next tabstop after widthSoFar
- return static_cast<int>((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
- }
- private:
- ScopedIntArrayRO mStops;
- const int mTabWidth;
- int mNumStops;
+// set text and set a number of parameters for creating a layout (width, tabstops, strategy)
+static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
+ jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
+ jintArray variableTabStops, jint defaultTabStop, jint strategy) {
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ b->resize(length);
+ env->GetCharArrayRegion(text, 0, length, b->buffer());
+ b->setText();
+ b->setLineWidths(firstWidth, firstWidthLineLimit, restWidth);
+ if (variableTabStops == nullptr) {
+ b->setTabStops(nullptr, 0, defaultTabStop);
+ } else {
+ ScopedIntArrayRO stops(env, variableTabStops);
+ b->setTabStops(stops.get(), stops.size(), defaultTabStop);
+ }
+ b->setStrategy(static_cast<BreakStrategy>(strategy));
+}
- // disable copying and assignment
- TabStops(const TabStops&);
- void operator=(const TabStops&);
-};
-
-enum PrimitiveType {
- kPrimitiveType_Box,
- kPrimitiveType_Glue,
- kPrimitiveType_Penalty,
- kPrimitiveType_Variable,
- kPrimitiveType_Wordbreak
-};
-
-static const float PENALTY_INFINITY = 1e7; // forced non-break, negative infinity is forced break
-
-struct Primitive {
- PrimitiveType type;
- int location;
- // 'Box' has width
- // 'Glue' has width
- // 'Penalty' has width and penalty
- // 'Variable' has tabStop
- // 'Wordbreak' has penalty
- union {
- struct {
- float width;
- float penalty;
- };
- const TabStops* tabStop;
- };
-};
-
-class LineWidth {
- public:
- LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) :
- mFirstWidth(firstWidth), mFirstWidthLineCount(firstWidthLineCount),
- mRestWidth(restWidth) {}
- float getLineWidth(int line) const {
- return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
- }
- private:
- const float mFirstWidth;
- const int mFirstWidthLineCount;
- const float mRestWidth;
-};
-
-class LineBreaker {
- public:
- LineBreaker(const std::vector<Primitive>& primitives,
- const LineWidth& lineWidth) :
- mPrimitives(primitives), mLineWidth(lineWidth) {}
- virtual ~LineBreaker() {}
- virtual void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const = 0;
- protected:
- const std::vector<Primitive>& mPrimitives;
- const LineWidth& mLineWidth;
-};
-
-class OptimizingLineBreaker : public LineBreaker {
- public:
- OptimizingLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
- LineBreaker(primitives, lineWidth) {}
- void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const {
- int numBreaks = mPrimitives.size();
- Node* opt = new Node[numBreaks];
- opt[0].prev = -1;
- opt[0].prevCount = 0;
- opt[0].width = 0;
- opt[0].demerits = 0;
- opt[0].flags = false;
- opt[numBreaks - 1].prev = -1;
- opt[numBreaks - 1].prevCount = 0;
-
- std::list<int> active;
- active.push_back(0);
- int lastBreak = 0;
- for (int i = 0; i < numBreaks; i++) {
- const Primitive& p = mPrimitives[i];
- if (p.type == kPrimitiveType_Penalty) {
- const bool finalBreak = (i + 1 == numBreaks);
- bool breakFound = false;
- Node bestBreak;
- for (std::list<int>::iterator it = active.begin(); it != active.end(); /* incrementing done in loop */) {
- const int pos = *it;
- bool flags;
- float width, printedWidth;
- const int lines = opt[pos].prevCount;
- const float maxWidth = mLineWidth.getLineWidth(lines);
- // we have to compute metrics every time --
- // we can't really precompute this stuff and just deal with breaks
- // because of the way tab characters work, this makes it computationally
- // harder, but this way, we can still optimize while treating tab characters
- // correctly
- computeMetrics(pos, i, &width, &printedWidth, &flags);
- if (printedWidth <= maxWidth) {
- float demerits = computeDemerits(maxWidth, printedWidth,
- finalBreak, p.penalty) + opt[pos].demerits;
- if (!breakFound || demerits < bestBreak.demerits) {
- bestBreak.prev = pos;
- bestBreak.prevCount = opt[pos].prevCount + 1;
- bestBreak.demerits = demerits;
- bestBreak.width = printedWidth;
- bestBreak.flags = flags;
- breakFound = true;
- }
- ++it;
- } else {
- active.erase(it++); // safe to delete like this
- }
- }
- if (p.penalty == -PENALTY_INFINITY) {
- active.clear();
- }
- if (breakFound) {
- opt[i] = bestBreak;
- active.push_back(i);
- lastBreak = i;
- }
- if (active.empty()) {
- // we can't give up!
- float width, printedWidth;
- bool flags;
- const int lines = opt[lastBreak].prevCount;
- const float maxWidth = mLineWidth.getLineWidth(lines);
- const int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, &width, &printedWidth, &flags);
-
- opt[breakIndex].prev = lastBreak;
- opt[breakIndex].prevCount = lines + 1;
- opt[breakIndex].demerits = 0; // doesn't matter, it's the only one
- opt[breakIndex].width = width;
- opt[breakIndex].flags = flags;
-
- active.push_back(breakIndex);
- lastBreak = breakIndex;
- i = breakIndex; // incremented by i++
- }
- }
- }
-
- int idx = numBreaks - 1;
- int count = opt[idx].prevCount;
- breaks->resize(count);
- widths->resize(count);
- flags->resize(count);
- while (opt[idx].prev != -1) {
- --count;
-
- (*breaks)[count] = mPrimitives[idx].location;
- (*widths)[count] = opt[idx].width;
- (*flags)[count] = opt[idx].flags;
-
- idx = opt[idx].prev;
- }
- delete[] opt;
- }
- private:
- inline void computeMetrics(int start, int end, float* width, float* printedWidth, bool* flags) const {
- bool f = false;
- float w = 0, pw = 0;
- for (int i = start; i < end; i++) {
- const Primitive& p = mPrimitives[i];
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- w += p.width;
- if (p.type == kPrimitiveType_Box) {
- pw = w;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- w = p.tabStop->width(w);
- f = true;
- }
- }
- *width = w;
- *printedWidth = pw;
- *flags = f;
- }
-
- inline float computeDemerits(float maxWidth, float width, bool finalBreak, float penalty) const {
- float deviation = finalBreak ? 0 : maxWidth - width;
- return (deviation * deviation) + penalty;
- }
-
- // returns end pos (chosen break), -1 if fail
- inline int desperateBreak(int start, int limit, float maxWidth, float* width, float* printedWidth, bool* flags) const {
- float w = 0, pw = 0;
- bool breakFound = false;
- int breakIndex = 0, firstTabIndex = INT_MAX;
- for (int i = start; i < limit; i++) {
- const Primitive& p = mPrimitives[i];
-
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- w += p.width;
- if (p.type == kPrimitiveType_Box) {
- pw = w;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- w = p.tabStop->width(w);
- firstTabIndex = std::min(firstTabIndex, i);
- }
-
- if (pw > maxWidth) {
- if (breakFound) {
- break;
- } else {
- // no choice, keep going
- }
- }
-
- // must make progress
- if (i > start && (p.type == kPrimitiveType_Penalty || p.type == kPrimitiveType_Wordbreak)) {
- breakFound = true;
- breakIndex = i;
- }
- }
-
- if (breakFound) {
- *width = w;
- *printedWidth = pw;
- *flags = (start <= firstTabIndex && firstTabIndex < breakIndex);
- return breakIndex;
- } else {
- return -1;
- }
- }
-
- struct Node {
- int prev; // set to sentinel value (-1) for initial node
- int prevCount; // number of breaks so far
- float demerits;
- float width;
- bool flags;
- };
-};
-
-class GreedyLineBreaker : public LineBreaker {
- public:
- GreedyLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
- LineBreaker(primitives, lineWidth) {}
- void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const {
- int lineNum = 0;
- float width = 0, printedWidth = 0;
- bool breakFound = false, goodBreakFound = false;
- int breakIndex = 0, goodBreakIndex = 0;
- float breakWidth = 0, goodBreakWidth = 0;
- int firstTabIndex = INT_MAX;
-
- float maxWidth = mLineWidth.getLineWidth(lineNum);
-
- const int numPrimitives = mPrimitives.size();
- // greedily fit as many characters as possible on each line
- // loop over all primitives, and choose the best break point
- // (if possible, a break point without splitting a word)
- // after going over the maximum length
- for (int i = 0; i < numPrimitives; i++) {
- const Primitive& p = mPrimitives[i];
-
- // update the current line width
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- width += p.width;
- if (p.type == kPrimitiveType_Box) {
- printedWidth = width;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- width = p.tabStop->width(width);
- // keep track of first tab character in the region we are examining
- // so we can determine whether or not a line contains a tab
- firstTabIndex = std::min(firstTabIndex, i);
- }
-
- // find the best break point for the characters examined so far
- if (printedWidth > maxWidth) {
- if (breakFound || goodBreakFound) {
- if (goodBreakFound) {
- // a true line break opportunity existed in the characters examined so far,
- // so there is no need to split a word
- i = goodBreakIndex; // no +1 because of i++
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(mPrimitives[goodBreakIndex].location);
- widths->push_back(goodBreakWidth);
- flags->push_back(firstTabIndex < goodBreakIndex);
- firstTabIndex = INT_MAX;
- } else {
- // must split a word because there is no other option
- i = breakIndex; // no +1 because of i++
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(mPrimitives[breakIndex].location);
- widths->push_back(breakWidth);
- flags->push_back(firstTabIndex < breakIndex);
- firstTabIndex = INT_MAX;
- }
- printedWidth = width = 0;
- goodBreakFound = breakFound = false;
- goodBreakWidth = breakWidth = 0;
- continue;
- } else {
- // no choice, keep going... must make progress by putting at least one
- // character on a line, even if part of that character is cut off --
- // there is no other option
- }
- }
-
- // update possible break points
- if (p.type == kPrimitiveType_Penalty && p.penalty < PENALTY_INFINITY) {
- // this does not handle penalties with width
-
- // handle forced line break
- if (p.penalty == -PENALTY_INFINITY) {
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(p.location);
- widths->push_back(printedWidth);
- flags->push_back(firstTabIndex < i);
- firstTabIndex = INT_MAX;
- printedWidth = width = 0;
- goodBreakFound = breakFound = false;
- goodBreakWidth = breakWidth = 0;
- continue;
- }
- if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
- breakFound = true;
- breakIndex = i;
- breakWidth = printedWidth;
- }
- if (i > goodBreakIndex && printedWidth <= maxWidth) {
- goodBreakFound = true;
- goodBreakIndex = i;
- goodBreakWidth = printedWidth;
- }
- } else if (p.type == kPrimitiveType_Wordbreak) {
- // only do this if necessary -- we don't want to break words
- // when possible, but sometimes it is unavoidable
- if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
- breakFound = true;
- breakIndex = i;
- breakWidth = printedWidth;
- }
- }
- }
-
- if (breakFound || goodBreakFound) {
- // output last break if there are more characters to output
- if (goodBreakFound) {
- breaks->push_back(mPrimitives[goodBreakIndex].location);
- widths->push_back(goodBreakWidth);
- flags->push_back(firstTabIndex < goodBreakIndex);
- } else {
- breaks->push_back(mPrimitives[breakIndex].location);
- widths->push_back(breakWidth);
- flags->push_back(firstTabIndex < breakIndex);
- }
- }
- }
-};
-
-static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
+static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
- jint recycleLength, const std::vector<jint>& breaks,
- const std::vector<jfloat>& widths, const std::vector<jboolean>& flags) {
- int bufferLength = breaks.size();
- if (recycleLength < bufferLength) {
+ jint recycleLength, size_t nBreaks, const jint* breaks,
+ const jfloat* widths, const jboolean* flags) {
+ if ((size_t)recycleLength < nBreaks) {
// have to reallocate buffers
- recycleBreaks = env->NewIntArray(bufferLength);
- recycleWidths = env->NewFloatArray(bufferLength);
- recycleFlags = env->NewBooleanArray(bufferLength);
+ recycleBreaks = env->NewIntArray(nBreaks);
+ recycleWidths = env->NewFloatArray(nBreaks);
+ recycleFlags = env->NewBooleanArray(nBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
}
// copy data
- env->SetIntArrayRegion(recycleBreaks, 0, breaks.size(), &breaks.front());
- env->SetFloatArrayRegion(recycleWidths, 0, widths.size(), &widths.front());
- env->SetBooleanArrayRegion(recycleFlags, 0, flags.size(), &flags.front());
-
- return bufferLength;
-}
-
-void computePrimitives(const jchar* textArr, const jfloat* widthsArr, jint length, const std::vector<int>& breaks,
- const TabStops& tabStopCalculator, std::vector<Primitive>* primitives) {
- int breaksSize = breaks.size();
- int breakIndex = 0;
- Primitive p;
- for (int i = 0; i < length; i++) {
- p.location = i;
- jchar c = textArr[i];
- if (c == CHAR_SPACE || c == CHAR_ZWSP) {
- p.type = kPrimitiveType_Glue;
- p.width = widthsArr[i];
- primitives->push_back(p);
- } else if (c == CHAR_TAB) {
- p.type = kPrimitiveType_Variable;
- p.tabStop = &tabStopCalculator; // shared between all variable primitives
- primitives->push_back(p);
- } else if (c != CHAR_NEWLINE) {
- while (breakIndex < breaksSize && breaks[breakIndex] < i) breakIndex++;
- p.width = 0;
- if (breakIndex < breaksSize && breaks[breakIndex] == i) {
- p.type = kPrimitiveType_Penalty;
- p.penalty = 0;
- } else {
- p.type = kPrimitiveType_Wordbreak;
- }
- if (widthsArr[i] != 0) {
- primitives->push_back(p);
- }
-
- p.type = kPrimitiveType_Box;
- p.width = widthsArr[i];
- primitives->push_back(p);
- }
- }
- // final break at end of everything
- p.location = length;
- p.type = kPrimitiveType_Penalty;
- p.width = 0;
- p.penalty = -PENALTY_INFINITY;
- primitives->push_back(p);
-}
-
-// sets the text on the builder
-static void nSetText(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, int length) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- b->resize(length);
- env->GetCharArrayRegion(text, 0, length, b->buffer());
- b->setText();
+ env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
+ env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
+ env->SetBooleanArrayRegion(recycleFlags, 0, nBreaks, flags);
}
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
- jint length,
- jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
- jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
jint recycleLength) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
- std::vector<int> breaks;
+ size_t nBreaks = b->computeBreaks();
- icu::BreakIterator* breakIterator = b->breakIterator();
- int loc = breakIterator->first();
- while ((loc = breakIterator->next()) != icu::BreakIterator::DONE) {
- breaks.push_back(loc);
- }
+ recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
+ nBreaks, b->getBreaks(), b->getWidths(), b->getFlags());
- // TODO: all these allocations can be moved into the builder
- std::vector<Primitive> primitives;
- TabStops tabStops(env, variableTabStops, defaultTabStop);
- computePrimitives(b->buffer(), b->widths(), length, breaks, tabStops, &primitives);
-
- LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
- std::vector<int> computedBreaks;
- std::vector<float> computedWidths;
- std::vector<unsigned char> computedFlags;
-
- if (optimize) {
- OptimizingLineBreaker breaker(primitives, lineWidth);
- breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
- } else {
- GreedyLineBreaker breaker(primitives, lineWidth);
- breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
- }
b->finish();
- return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
- computedBreaks, computedWidths, computedFlags);
+ return static_cast<jint>(nBreaks);
}
static jlong nNewBuilder(JNIEnv*, jclass) {
- return reinterpret_cast<jlong>(new Builder);
+ return reinterpret_cast<jlong>(new LineBreaker);
}
static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
- delete reinterpret_cast<Builder*>(nativePtr);
+ delete reinterpret_cast<LineBreaker*>(nativePtr);
}
static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
b->finish();
}
static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
ScopedIcuLocale icuLocale(env, javaLocaleName);
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
if (icuLocale.valid()) {
b->setLocale(icuLocale.locale());
}
}
-float Builder::measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
- bool isRtl) {
- Layout layout;
- int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- // TODO: should we provide more context?
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, mTextBuf.data() + start, 0,
- end - start, end - start);
- layout.getAdvances(mWidthBuf.data() + start);
- return layout.getAdvance();
-}
-
-void Builder::addReplacement(size_t start, size_t end, float width) {
- mWidthBuf[start] = width;
- std::fill(&mWidthBuf[start + 1], &mWidthBuf[end], 0.0f);
-}
-
// Basically similar to Paint.getTextRunAdvances but with C++ interface
static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr,
jlong nativePaint, jlong nativeTypeface, jint start, jint end, jboolean isRtl) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(nativeTypeface);
- return b->measureStyleRun(paint, typeface, start, end, isRtl);
+ FontCollection *font;
+ MinikinPaint minikinPaint;
+ FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+ return b->addStyleRun(&minikinPaint, font, style, start, end, isRtl);
}
// Accept width measurements for the run, passed in from Java
static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr,
jint start, jint end, jfloatArray widths) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- env->GetFloatArrayRegion(widths, start, end - start, b->widths() + start);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ env->GetFloatArrayRegion(widths, start, end - start, b->charWidths() + start);
+ b->addStyleRun(nullptr, nullptr, FontStyle{}, start, end, false);
}
static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
jint start, jint end, jfloat width) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
b->addReplacement(start, end, width);
}
static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- env->SetFloatArrayRegion(widths, 0, b->size(), b->widths());
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
}
static JNINativeMethod gMethods[] = {
@@ -684,12 +165,12 @@
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
{"nSetLocale", "(JLjava/lang/String;)V", (void*) nSetLocale},
- {"nSetText", "(J[CI)V", (void*) nSetText},
+ {"nSetupParagraph", "(J[CIFIF[III)V", (void*) nSetupParagraph},
{"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
{"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
- {"nComputeLineBreaks", "(JIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+ {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
(void*) nComputeLineBreaks}
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4d6b5f6..851c4bf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -77,6 +77,8 @@
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
+ <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
+
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
@@ -2607,7 +2609,8 @@
android:protectionLevel="signature|system" />
<!-- @SystemApi Allows an application to collect component usage
- statistics @hide -->
+ statistics
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
new file mode 100644
index 0000000..f247919
--- /dev/null
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/floating_toolbar_height"
+ android:elevation="2dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:background="@android:color/background_light" />
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
new file mode 100644
index 0000000..9fa13bd
--- /dev/null
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, 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.
+*/
+-->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingLeft="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingRight="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:fontFamily="sans-serif"
+ android:textSize="@dimen/floating_toolbar_text_size"
+ android:textAllCaps="true"
+ android:background="?attr/selectableItemBackground" />
\ No newline at end of file
diff --git a/core/res/res/layout/floating_popup_open_overflow_button.xml b/core/res/res/layout/floating_popup_open_overflow_button.xml
new file mode 100644
index 0000000..4c1176c
--- /dev/null
+++ b/core/res/res/layout/floating_popup_open_overflow_button.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, 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.
+*/
+-->
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+ android:minHeight="@dimen/floating_toolbar_height"
+ android:src="@drawable/ic_menu_moreoverflow_material"
+ android:contentDescription="@string/action_menu_overflow_description"
+ android:background="?attr/selectableItemBackgroundBorderless" />
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
index 5cadc2a..75b1b53 100644
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -29,4 +29,6 @@
<string-array name="wfcOperatorErrorMessages">
<item>Wi-Fi Calling isn\'t available. Contact your carrier to enable Wi-Fi Calling.</item>
</string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index aefb67c..283c237 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -389,13 +389,12 @@
with the same {@link android.R.attr#taskAffinity} as it has. -->
<attr name="allowTaskReparenting" format="boolean" />
- <!-- Declare that this application may use cleartext traffic (e.g., HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS).
- Defaults to true. If set to false {@code false}, the app declares that it does not
- intend to use cleartext network traffic, in which case platform components (e.g.,
- HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use
- cleartext traffic. Third-party libraries are encouraged to honor this flag as well.
- @hide -->
+ <!-- Declare that this application may use cleartext traffic, such as HTTP rather than HTTPS;
+ WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS.
+ Defaults to true. If set to false {@code false}, the application declares that it does not
+ intend to use cleartext network traffic, in which case platform components (e.g. HTTP
+ stacks, {@code WebView}, {@code MediaPlayer}) will refuse applications's requests to use
+ cleartext traffic. Third-party libraries are encouraged to honor this flag as well. -->
<attr name="usesCleartextTraffic" format="boolean" />
<!-- Declare that code from this application will need to be loaded into other
@@ -1164,13 +1163,13 @@
"com.google". -->
<attr name="requiredAccountType" format="string"/>
<attr name="isGame" />
- <!-- Declare that this application may use cleartext traffic (e.g., HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS).
- Defaults to true. If set to false {@code false}, the app declares that it does not
- intend to use cleartext network traffic, in which case platform components (e.g.,
- HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use
- cleartext traffic. Third-party libraries are encouraged to honor this flag as well.
- @hide -->
+ <!-- Declare that this application may use cleartext traffic, such as HTTP rather than
+ HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or
+ TLS). Defaults to true. If set to false {@code false}, the application declares that it
+ does not intend to use cleartext network traffic, in which case platform components
+ (e.g. HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse applications's
+ requests to use cleartext traffic. Third-party libraries are encouraged to honor this
+ flag as well. -->
<attr name="usesCleartextTraffic" />
<attr name="multiArch" />
<attr name="extractNativeLibs" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 37c9598..1b2e952 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1112,6 +1112,18 @@
device does not support multiple advertisement-->
<integer translatable="false" name="config_bluetooth_max_advertisers">0</integer>
+ <!-- Idle current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_idle_cur_ma">1</integer>
+
+ <!-- Rx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_rx_cur_ma">2</integer>
+
+ <!-- Tx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_tx_cur_ma">3</integer>
+
+ <!-- Operating volatage for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
+
<!-- The default data-use polling period. -->
<integer name="config_datause_polling_period_sec">600</integer>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6c6d2cc..3431f35 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -386,4 +386,11 @@
<item type="dimen" format="float" name="ambient_shadow_alpha">0.075</item>
<item type="dimen" format="float" name="spot_shadow_alpha">0.15</item>
+ <!-- Floating toolbar dimensions -->
+ <dimen name="floating_toolbar_height">48dp</dimen>
+ <dimen name="floating_toolbar_menu_button_side_padding">8dp</dimen>
+ <dimen name="floating_toolbar_text_size">14sp</dimen>
+ <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen>
+ <dimen name="floating_toolbar_default_width">250dp</dimen>
+ <dimen name="floating_toolbar_minimum_overflow_height">192dp</dimen>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 6108b27..7e963954 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -93,4 +93,5 @@
<item type="id" name="undo" />
<item type="id" name="redo" />
<item type="id" name="replaceText" />
+ <item type="id" name="accessibility_action_show_on_screen" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5e4b039..ef7bfaf 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2652,4 +2652,5 @@
<public type="attr" name="colorBackgroundFloating" />
<public type="attr" name="extractNativeLibs" />
+ <public type="attr" name="usesCleartextTraffic" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7672e93..88225bd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -251,6 +251,8 @@
<string-array name="wfcOperatorErrorCodes" translatable="false" />
<!-- WFC Operator Error Messages -->
<string-array name="wfcOperatorErrorMessages" />
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s</string>
<!--
{0} is one of "bearerServiceCode*"
@@ -2226,6 +2228,36 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_useFingerprint">Allows the app to use fingerprint hardware for authentication</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
+ <string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
+ <string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
+ <string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
+ <!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_acquired_vendor">
+ <item>Vendor-specific acquisition error message 0</item>
+ </string-array>
+
+ <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
+ <string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware can't be accessed -->
+ <string name="fingerprint_error_hw_not_available">Hardware not available.</string>
+ <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
+ <string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_vendor">Fingerprint time out reached. Try again.</string>
+ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_error_vendor">
+ <item>Vendor-specifc error message.</item>
+ </string-array>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readSyncSettings">read sync settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c4e9e8e..67d54729 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -349,6 +349,10 @@
<java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
+ <java-symbol type="integer" name="config_bluetooth_idle_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_rx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_tx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_drawLockTimeoutMillis" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -756,6 +760,7 @@
<java-symbol type="string" name="wfcRegErrorTitle" />
<java-symbol type="array" name="wfcOperatorErrorCodes" />
<java-symbol type="array" name="wfcOperatorErrorMessages" />
+ <java-symbol type="string" name="wfcSpnFormat" />
<java-symbol type="string" name="policydesc_disableCamera" />
<java-symbol type="string" name="policydesc_encryptedStorage" />
<java-symbol type="string" name="policydesc_expirePassword" />
@@ -2061,6 +2066,19 @@
<!-- From KeyguardServiceDelegate -->
<java-symbol type="string" name="config_keyguardComponent" />
+ <!-- Fingerprint messages -->
+ <java-symbol type="string" name="fingerprint_error_unable_to_process" />
+ <java-symbol type="string" name="fingerprint_error_hw_not_available" />
+ <java-symbol type="string" name="fingerprint_error_no_space" />
+ <java-symbol type="string" name="fingerprint_error_timeout" />
+ <java-symbol type="array" name="fingerprint_error_vendor" />
+ <java-symbol type="string" name="fingerprint_acquired_partial" />
+ <java-symbol type="string" name="fingerprint_acquired_insufficient" />
+ <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
+ <java-symbol type="string" name="fingerprint_acquired_too_slow" />
+ <java-symbol type="string" name="fingerprint_acquired_too_fast" />
+ <java-symbol type="array" name="fingerprint_acquired_vendor" />
+
<!-- From various Material changes -->
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
@@ -2174,4 +2192,17 @@
<java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Day" />
<java-symbol type="dimen" name="day_picker_padding_top"/>
<java-symbol type="dimen" name="date_picker_day_of_week_height"/>
+
+ <java-symbol type="id" name="accessibility_action_show_on_screen" />
+
+ <!-- Floating toolbar -->
+ <java-symbol type="layout" name="floating_popup_container" />
+ <java-symbol type="layout" name="floating_popup_menu_button" />
+ <java-symbol type="layout" name="floating_popup_open_overflow_button" />
+ <java-symbol type="dimen" name="floating_toolbar_height" />
+ <java-symbol type="dimen" name="floating_toolbar_menu_button_side_padding" />
+ <java-symbol type="dimen" name="floating_toolbar_text_size" />
+ <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" />
+ <java-symbol type="dimen" name="floating_toolbar_default_width" />
+ <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" />
</resources>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index db489f6..a56e87e 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -50,8 +50,8 @@
* </p>
* <p>
* First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
- * Note that we allow the animation happen on the group's attributes and path's
- * attributes, which requires they are uniquely named in this xml file. Groups
+ * Note that we allow the animation to happen on the group's attributes and path's
+ * attributes, which requires they are uniquely named in this XML file. Groups
* and paths without animations do not need names.
* </p>
* <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
@@ -74,7 +74,7 @@
* </vector>
* </pre></li>
* <p>
- * Second is the AnimatedVectorDrawable's xml file, which defines the target
+ * Second is the AnimatedVectorDrawable's XML file, which defines the target
* VectorDrawable, the target paths and groups to animate, the properties of the
* path and group to animate and the animations defined as the ObjectAnimators
* or AnimatorSets.
@@ -93,7 +93,7 @@
* </animated-vector>
* </pre></li>
* <p>
- * Last is the Animator xml file, which is the same as a normal ObjectAnimator
+ * Last is the Animator XML file, which is the same as a normal ObjectAnimator
* or AnimatorSet.
* To complete this example, here are the 2 animator files used in avd.xml:
* rotation.xml and path_morph.xml.
@@ -110,7 +110,7 @@
* the other. Note that the paths must be compatible for morphing.
* In more details, the paths should have exact same length of commands , and
* exact same length of parameters for each commands.
- * Note that the path string are better stored in strings.xml for reusing.
+ * Note that the path strings are better stored in strings.xml for reusing.
* <pre>
* <set xmlns:android="http://schemas.android.com/apk/res/android">
* <objectAnimator
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 39a33ce..b827682 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -56,21 +56,21 @@
* <p/>
* <dt><code><vector></code></dt>
* <dl>
- * <dd>Used to defined a vector drawable
+ * <dd>Used to define a vector drawable
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of this vector drawable.</dd>
* <dt><code>android:width</code></dt>
- * <dd>Used to defined the intrinsic width of the drawable.
+ * <dd>Used to define the intrinsic width of the drawable.
* This support all the dimension units, normally specified with dp.</dd>
* <dt><code>android:height</code></dt>
- * <dd>Used to defined the intrinsic height the drawable.
+ * <dd>Used to define the intrinsic height the drawable.
* This support all the dimension units, normally specified with dp.</dd>
* <dt><code>android:viewportWidth</code></dt>
- * <dd>Used to defined the width of the viewport space. Viewport is basically
+ * <dd>Used to define the width of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
* <dt><code>android:viewportHeight</code></dt>
- * <dd>Used to defined the height of the viewport space. Viewport is basically
+ * <dd>Used to define the height of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
* <dt><code>android:tint</code></dt>
* <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
@@ -120,7 +120,7 @@
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the path.</dd>
* <dt><code>android:pathData</code></dt>
- * <dd>Defines path string. This is using exactly same format as "d" attribute
+ * <dd>Defines path data using exactly same format as "d" attribute
* in the SVG's path data. This is defined in the viewport space.</dd>
* <dt><code>android:fillColor</code></dt>
* <dd>Defines the color to fill the path (none if not present).</dd>
@@ -156,7 +156,7 @@
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the clip path.</dd>
* <dt><code>android:pathData</code></dt>
- * <dd>Defines clip path string. This is using exactly same format as "d" attribute
+ * <dd>Defines clip path using the same format as "d" attribute
* in the SVG's path data.</dd>
* </dl></dd>
* </dl>
@@ -249,8 +249,8 @@
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
- if (bounds.width() == 0 || bounds.height() == 0) {
- // too small to draw
+ if (bounds.width() <= 0 || bounds.height() <= 0) {
+ // Nothing to draw
return;
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfbf028..957e3c1 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -25,6 +25,7 @@
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.util.Log;
@@ -403,7 +404,7 @@
return generateKey(alias, args, UID_SELF, flags, outCharacteristics);
}
- public int getKeyCharacteristics(String alias, byte[] clientId, byte[] appId,
+ public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
KeyCharacteristics outCharacteristics) {
try {
return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
@@ -429,7 +430,8 @@
return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
}
- public ExportResult exportKey(String alias, int format, byte[] clientId, byte[] appId) {
+ public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
+ KeymasterBlob appId) {
try {
return mBinder.exportKey(alias, format, clientId, appId);
} catch (RemoteException e) {
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index f0b07a6..f755bb0 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -25,6 +25,7 @@
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.test.ActivityUnitTestCase;
@@ -712,10 +713,8 @@
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
- args.addBlob(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
- RSAKeyGenParameterSpec.F4.toByteArray());
+ args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+ RSAKeyGenParameterSpec.F4.longValue());
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -744,6 +743,7 @@
public void testAppId() throws Exception {
String name = "test";
+ byte[] id = new byte[] {0x01, 0x02, 0x03};
KeymasterArguments args = new KeymasterArguments();
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
@@ -751,10 +751,9 @@
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, new byte[] {0x01, 0x02, 0x03});
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
- args.addBlob(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
- RSAKeyGenParameterSpec.F4.toByteArray());
+ args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
+ args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+ RSAKeyGenParameterSpec.F4.longValue());
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -764,7 +763,7 @@
mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
assertEquals("getKeyCharacteristics should succeed with application ID",
KeyStore.NO_ERROR,
- mKeyStore.getKeyCharacteristics(name, new byte[] {0x01, 0x02, 0x03}, null,
+ mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null,
outCharacteristics));
}
@@ -789,8 +788,6 @@
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -798,8 +795,6 @@
KeymasterArguments out = new KeymasterArguments();
args = new KeymasterArguments();
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
true, args, out);
IBinder token = result.token;
@@ -888,8 +883,6 @@
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -897,8 +890,6 @@
KeymasterArguments out = new KeymasterArguments();
args = new KeymasterArguments();
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
true, args, out);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 9509c48..30d3f41 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -197,6 +197,7 @@
case SkPath::kLine_Verb:
arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
break;
+ case SkPath::kConic_Verb:
case SkPath::kQuad_Verb:
arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 66de333..d9d06bf 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -380,6 +380,7 @@
const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
+ if (mShadowCache.get(key)) return;
sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
if (mShadowProcessor == nullptr) {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 259fe37..99b7bee 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,6 +20,7 @@
import java.nio.ByteBuffer;
import java.util.Iterator;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.Handler;
@@ -313,8 +314,14 @@
audioParamCheck(attributes.getCapturePreset(), rate, encoding);
- mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask());
- mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
+ int channelMask = AudioFormat.CHANNEL_IN_DEFAULT;
+ if ((format.getPropertySetMask()
+ & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
+ {
+ channelMask = format.getChannelMask();
+ }
+ mChannelCount = AudioFormat.channelCountFromInChannelMask(channelMask);
+ mChannelMask = getChannelMaskFromLegacyConfig(channelMask, false);
audioBuffSizeCheck(bufferSizeInBytes);
@@ -335,6 +342,161 @@
mState = STATE_INITIALIZED;
}
+ /**
+ * Builder class for {@link AudioRecord} objects.
+ * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
+ * recording preset (a.k.a. recording source) and audio format parameters, you indicate which of
+ * those vary from the default behavior on the device.
+ * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
+ * parameters, to be used by a new <code>AudioRecord</code> instance:
+ *
+ * <pre class="prettyprint">
+ * AudioRecord recorder = new AudioRecord.Builder()
+ * .setCapturePreset(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
+ * .setAudioFormat(new AudioFormat.Builder()
+ * .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ * .setSampleRate(32000)
+ * .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+ * .build())
+ * .setBufferSize(2*minBuffSize)
+ * .build();
+ * </pre>
+ * <p>
+ * If the capture preset is not set with {@link #setCapturePreset(int)},
+ * {@link MediaRecorder.AudioSource#DEFAULT} is used.
+ * <br>If the audio format is not specified or is incomplete, its sample rate will be the
+ * default output sample rate of the device (see
+ * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
+ * {@link AudioFormat#CHANNEL_IN_DEFAULT}.
+ * <br>Failing to set an adequate buffer size with {@link #setBufferSizeInBytes(int)} will
+ * prevent the successful creation of an <code>AudioRecord</code> instance.
+ */
+ public static class Builder {
+ private AudioAttributes mAttributes;
+ private AudioFormat mFormat;
+ private int mBufferSizeInBytes;
+ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
+
+ /**
+ * Constructs a new Builder with the default values as described above.
+ */
+ public Builder() {
+ }
+
+ /**
+ * @param preset the capture preset (also referred to as the recording source).
+ * See {@link MediaRecorder.AudioSource} for the supported capture preset definitions.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setCapturePreset(int preset) throws IllegalArgumentException {
+ if ( (preset < MediaRecorder.AudioSource.DEFAULT) ||
+ (preset > MediaRecorder.getAudioSourceMax()) ) {
+ throw new IllegalArgumentException("Invalid audio source " + preset);
+ }
+ mAttributes = new AudioAttributes.Builder()
+ .setInternalCapturePreset(preset)
+ .build();
+ return this;
+ }
+
+ /**
+ * @hide
+ * To be only used by system components. Allows specifying non-public capture presets
+ * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
+ * preset to be used.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ @SystemApi
+ public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
+ throws IllegalArgumentException {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+ }
+ if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
+ throw new IllegalArgumentException(
+ "No valid capture preset in AudioAttributes argument");
+ }
+ // keep reference, we only copy the data when building
+ mAttributes = attributes;
+ return this;
+ }
+
+ /**
+ * Sets the format of the audio data to be captured.
+ * @param format a non-null {@link AudioFormat} instance
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
+ if (format == null) {
+ throw new IllegalArgumentException("Illegal null AudioFormat argument");
+ }
+ // keep reference, we only copy the data when building
+ mFormat = format;
+ return this;
+ }
+
+ /**
+ * Sets the total size (in bytes) of the buffer where audio data is written
+ * during the recording. New audio data can be read from this buffer in smaller chunks
+ * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
+ * required buffer size for the successful creation of an AudioRecord instance.
+ * Using values smaller than getMinBufferSize() will result in an initialization failure.
+ * @param bufferSizeInBytes a value strictly greater than 0
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
+ if (bufferSizeInBytes <= 0) {
+ throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
+ }
+ mBufferSizeInBytes = bufferSizeInBytes;
+ return this;
+ }
+
+ /**
+ * @hide
+ * To be only used by system components.
+ * @param sessionId ID of audio session the AudioRecord must be attached to, or
+ * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
+ * construction time.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ @SystemApi
+ public Builder setSessionId(int sessionId) throws IllegalArgumentException {
+ if (sessionId < 0) {
+ throw new IllegalArgumentException("Invalid session ID " + sessionId);
+ }
+ mSessionId = sessionId;
+ return this;
+ }
+
+ /**
+ * @return a new {@link AudioRecord} instance initialized with all the parameters set
+ * on this <code>Builder</code>
+ * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
+ * were incompatible, or if they are not supported by the device.
+ */
+ public AudioRecord build() throws UnsupportedOperationException {
+ if (mFormat == null) {
+ mFormat = new AudioFormat.Builder().build();
+ }
+ if (mAttributes == null) {
+ mAttributes = new AudioAttributes.Builder()
+ .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
+ .build();
+ }
+ try {
+ return new AudioRecord(mAttributes, mFormat, mBufferSizeInBytes, mSessionId);
+ } catch (IllegalArgumentException e) {
+ throw new UnsupportedOperationException(e.getMessage());
+ }
+ }
+ }
+
// Convenience method for the constructor's parameter checks.
// This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
// IllegalArgumentException-s are thrown
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
index ddbffc2..afc3ca7 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/java/android/media/MediaDescription.java
@@ -41,9 +41,13 @@
* Extras for opaque use by apps/system.
*/
private final Bundle mExtras;
+ /**
+ * A Uri to identify this content.
+ */
+ private final Uri mMediaUri;
private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
- CharSequence description, Bitmap icon, Uri iconUri, Bundle extras) {
+ CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
mMediaId = mediaId;
mTitle = title;
mSubtitle = subtitle;
@@ -51,6 +55,7 @@
mIcon = icon;
mIconUri = iconUri;
mExtras = extras;
+ mMediaUri = mediaUri;
}
private MediaDescription(Parcel in) {
@@ -61,6 +66,7 @@
mIcon = in.readParcelable(null);
mIconUri = in.readParcelable(null);
mExtras = in.readBundle();
+ mMediaUri = in.readParcelable(null);
}
/**
@@ -125,6 +131,15 @@
return mExtras;
}
+ /**
+ * Returns a Uri representing this content or null.
+ *
+ * @return A media Uri or null.
+ */
+ public @Nullable Uri getMediaUri() {
+ return mMediaUri;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -139,6 +154,7 @@
dest.writeParcelable(mIcon, flags);
dest.writeParcelable(mIconUri, flags);
dest.writeBundle(mExtras);
+ dest.writeParcelable(mMediaUri, flags);
}
@Override
@@ -170,6 +186,7 @@
private Bitmap mIcon;
private Uri mIconUri;
private Bundle mExtras;
+ private Uri mMediaUri;
/**
* Creates an initially empty builder.
@@ -257,9 +274,20 @@
return this;
}
+ /**
+ * Sets the media uri.
+ *
+ * @param mediaUri The content's {@link Uri} for the item or null.
+ * @return this
+ */
+ public Builder setMediaUri(@Nullable Uri mediaUri) {
+ mMediaUri = mediaUri;
+ return this;
+ }
+
public MediaDescription build() {
return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
- mExtras);
+ mExtras, mMediaUri);
}
}
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 58c86f2..058cfd2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -157,8 +157,11 @@
}
/**
- * Defines the audio source. These constants are used with
- * {@link MediaRecorder#setAudioSource(int)}.
+ * Defines the audio source.
+ * An audio source defines both a default physical source of audio signal, and a recording
+ * configuration; it's also known as a capture preset. These constants are for instance used
+ * in {@link MediaRecorder#setAudioSource(int)} or
+ * {@link AudioRecord.Builder#setCapturePreset(int)}.
*/
public final class AudioSource {
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 49087b0..adb6b06 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -15,8 +15,8 @@
package android.media.session;
-import android.media.Rating;
import android.content.Intent;
+import android.media.Rating;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -30,8 +30,9 @@
// These callbacks are for the TransportPerformer
void onPlay();
- void onPlayFromMediaId(String uri, in Bundle extras);
+ void onPlayFromMediaId(String mediaId, in Bundle extras);
void onPlayFromSearch(String query, in Bundle extras);
+ void onPlayFromUri(in Uri uri, in Bundle extras);
void onSkipToTrack(long id);
void onPause();
void onStop();
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e2d06d3..8d58a60 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -23,9 +23,9 @@
import android.media.routing.IMediaRouterDelegate;
import android.media.routing.IMediaRouterStateCallback;
import android.media.session.ISessionControllerCallback;
+import android.media.session.MediaSession;
import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -55,8 +55,9 @@
// These commands are for the TransportControls
void play();
- void playFromMediaId(String uri, in Bundle extras);
+ void playFromMediaId(String mediaId, in Bundle extras);
void playFromSearch(String string, in Bundle extras);
+ void playFromUri(in Uri uri, in Bundle extras);
void skipToQueueItem(long id);
void pause();
void stop();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index c23a139..8def486 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -615,9 +615,9 @@
}
/**
- * Request that the player start playback for a specific {@link Uri}.
+ * Request that the player start playback for a specific media id.
*
- * @param mediaId The uri of the requested media.
+ * @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
*/
@@ -656,6 +656,25 @@
}
/**
+ * Request that the player start playback for a specific {@link Uri}.
+ *
+ * @param uri The URI of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be played.
+ */
+ public void playFromUri(Uri uri, Bundle extras) {
+ if (uri == null || Uri.EMPTY.equals(uri)) {
+ throw new IllegalArgumentException(
+ "You must specify a non-empty Uri for playFromUri.");
+ }
+ try {
+ mSessionBinder.playFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+ }
+ }
+
+ /**
* Play an item with a specific id in the play queue. If you specify an
* id that is not in the play queue, the behavior is undefined.
*/
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cc602c9..cee82b4 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -30,6 +30,7 @@
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.routing.MediaRouter;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -541,6 +542,10 @@
postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
}
+ private void dispatchPlayFromUri(Uri uri, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+ }
+
private void dispatchSkipToItem(long id) {
postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id);
}
@@ -833,6 +838,12 @@
}
/**
+ * Override to handle requests to play a specific media item represented by a URI.
+ */
+ public void onPlayFromUri(Uri uri, Bundle extras) {
+ }
+
+ /**
* Override to handle requests to play an item with a given id from the
* play queue.
*/
@@ -961,6 +972,14 @@
}
@Override
+ public void onPlayFromUri(Uri uri, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPlayFromUri(uri, extras);
+ }
+ }
+
+ @Override
public void onSkipToTrack(long id) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1171,6 +1190,7 @@
private static final int MSG_COMMAND = 15;
private static final int MSG_ADJUST_VOLUME = 16;
private static final int MSG_SET_VOLUME = 17;
+ private static final int MSG_PLAY_URI = 18;
private MediaSession.Callback mCallback;
@@ -1210,6 +1230,9 @@
case MSG_PLAY_SEARCH:
mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
break;
+ case MSG_PLAY_URI:
+ mCallback.onPlayFromUri((Uri) msg.obj, msg.getData());
+ break;
case MSG_SKIP_TO_ITEM:
mCallback.onSkipToQueueItem((Long) msg.obj);
break;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 6807e7f..bbe04b5 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -126,6 +126,13 @@
public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
/**
+ * Indicates this session supports the play from URI command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PLAY_FROM_URI = 1 << 13;
+
+ /**
* This is the default playback state and indicates that no media has been
* added yet, or the performer has been reset and has no content to play.
*
@@ -353,6 +360,11 @@
* <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
* <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
* <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
* </ul>
*/
public long getActions() {
@@ -868,6 +880,11 @@
* <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
* <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
* <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
* </ul>
*
* @param actions The set of actions allowed.
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index e95e5ec..165b11e 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -42,10 +42,21 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".StandaloneActivity"
+ android:theme="@style/StandaloneTheme"
+ android:icon="@drawable/ic_doc_text"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
<provider
android:name=".RecentsProvider"
android:authorities="com.android.documentsui.recents"
- android:exported="false" />
+ android:exported="false"/>
<receiver android:name=".PackageReceiver">
<intent-filter>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 04692f6..bf01bf1 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -43,4 +43,22 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
</style>
+ <style name="StandaloneTheme" parent="android:Theme.Light">
+ <item name="android:actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
+ <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
+
+ <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_900</item>
+ <item name="android:colorPrimary">@*android:color/material_blue_grey_800</item>
+ <item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
+
+ <item name="android:listDivider">@*android:drawable/list_divider_material</item>
+
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowActionModeOverlay">true</item>
+ <item name="android:windowNoTitle">true</item>
+
+ <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ </style>
+
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
new file mode 100644
index 0000000..a8a0c1d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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.documentsui;
+
+import java.util.HashMap;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.pm.ResolveInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.google.common.collect.Maps;
+
+abstract class BaseActivity extends Activity {
+
+ public abstract State getDisplayState();
+ public abstract RootInfo getCurrentRoot();
+ public abstract void onStateChanged();
+ public abstract void setRootsDrawerOpen(boolean open);
+ public abstract void onDocumentPicked(DocumentInfo doc);
+ public abstract void onDocumentsPicked(List<DocumentInfo> docs);
+ public abstract DocumentInfo getCurrentDirectory();
+ public abstract void setPending(boolean pending);
+ public abstract void onStackPicked(DocumentStack stack);
+ public abstract void onPickRequested(DocumentInfo pickTarget);
+ public abstract void onAppPicked(ResolveInfo info);
+ public abstract void onRootPicked(RootInfo root, boolean closeDrawer);
+ public abstract void onSaveRequested(DocumentInfo replaceTarget);
+ public abstract void onSaveRequested(String mimeType, String displayName);
+
+ public static BaseActivity get(Fragment fragment) {
+ return (BaseActivity) fragment.getActivity();
+ }
+
+ public static class State implements android.os.Parcelable {
+ public int action;
+ public String[] acceptMimes;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ public boolean allowMultiple = false;
+ public boolean showSize = false;
+ public boolean localOnly = false;
+ public boolean forceAdvanced = false;
+ public boolean showAdvanced = false;
+ public boolean stackTouched = false;
+ public boolean restored = false;
+
+ /** Current user navigation stack; empty implies recents. */
+ public DocumentStack stack = new DocumentStack();
+ /** Currently active search, overriding any stack. */
+ public String currentSearch;
+
+ /** Instance state for every shown directory */
+ public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
+ public static final int ACTION_GET_CONTENT = 3;
+ public static final int ACTION_OPEN_TREE = 4;
+ public static final int ACTION_MANAGE = 5;
+ public static final int ACTION_MANAGE_ALL = 6;
+
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
+
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(action);
+ out.writeInt(userMode);
+ out.writeStringArray(acceptMimes);
+ out.writeInt(userSortOrder);
+ out.writeInt(allowMultiple ? 1 : 0);
+ out.writeInt(showSize ? 1 : 0);
+ out.writeInt(localOnly ? 1 : 0);
+ out.writeInt(forceAdvanced ? 1 : 0);
+ out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
+ out.writeInt(restored ? 1 : 0);
+ DurableUtils.writeToParcel(out, stack);
+ out.writeString(currentSearch);
+ out.writeMap(dirState);
+ }
+
+ public static final Creator<State> CREATOR = new Creator<State>() {
+ @Override
+ public State createFromParcel(Parcel in) {
+ final State state = new State();
+ state.action = in.readInt();
+ state.userMode = in.readInt();
+ state.acceptMimes = in.readStringArray();
+ state.userSortOrder = in.readInt();
+ state.allowMultiple = in.readInt() != 0;
+ state.showSize = in.readInt() != 0;
+ state.localOnly = in.readInt() != 0;
+ state.forceAdvanced = in.readInt() != 0;
+ state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
+ state.restored = in.readInt() != 0;
+ DurableUtils.readFromParcel(in, state.stack);
+ state.currentSearch = in.readString();
+ in.readMap(state.dirState, null);
+ return state;
+ }
+
+ @Override
+ public State[] newArray(int size) {
+ return new State[size];
+ }
+ };
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index ba8c35f..1a17ee0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -70,7 +70,7 @@
public void onClick(DialogInterface dialog, int which) {
final String displayName = text1.getText().toString();
- final DocumentsActivity activity = (DocumentsActivity) getActivity();
+ final BaseActivity activity = (BaseActivity) getActivity();
final DocumentInfo cwd = activity.getCurrentDirectory();
new CreateDirectoryTask(activity, cwd, displayName).executeOnExecutor(
@@ -83,12 +83,12 @@
}
private class CreateDirectoryTask extends AsyncTask<Void, Void, DocumentInfo> {
- private final DocumentsActivity mActivity;
+ private final BaseActivity mActivity;
private final DocumentInfo mCwd;
private final String mDisplayName;
public CreateDirectoryTask(
- DocumentsActivity activity, DocumentInfo cwd, String displayName) {
+ BaseActivity activity, DocumentInfo cwd, String displayName) {
mActivity = activity;
mCwd = cwd;
mDisplayName = displayName;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 39c2252..f55912c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -17,12 +17,12 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
-import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
-import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.MODE_GRID;
+import static com.android.documentsui.BaseActivity.State.MODE_LIST;
+import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -76,7 +76,7 @@
import android.widget.TextView;
import android.widget.Toast;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
@@ -301,13 +301,13 @@
state.derivedMode = result.mode;
}
state.derivedSortOrder = result.sortOrder;
- ((DocumentsActivity) context).onStateChanged();
+ ((BaseActivity) context).onStateChanged();
updateDisplayState();
// When launched into empty recents, show drawer
if (mType == TYPE_RECENT_OPEN && mAdapter.isEmpty() && !state.stackTouched) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
+ ((BaseActivity) context).setRootsDrawerOpen(true);
}
// Restore any previous instance state
@@ -386,7 +386,7 @@
// Mode change is just visual change; no need to kick loader, and
// deliver change event immediately.
state.derivedMode = state.userMode;
- ((DocumentsActivity) getActivity()).onStateChanged();
+ ((BaseActivity) getActivity()).onStateChanged();
updateDisplayState();
}
@@ -441,7 +441,7 @@
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
if (isDocumentEnabled(docMimeType, docFlags)) {
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+ ((BaseActivity) getActivity()).onDocumentPicked(doc);
}
}
}
@@ -487,7 +487,7 @@
final int id = item.getItemId();
if (id == R.id.menu_open) {
- DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
+ BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
mode.finish();
return true;
@@ -616,7 +616,7 @@
}
private static State getDisplayState(Fragment fragment) {
- return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
+ return ((BaseActivity) fragment.getActivity()).getDisplayState();
}
private static abstract class Footer {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 163615d..8e4ec8c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -17,11 +17,11 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -36,7 +36,7 @@
import android.provider.DocumentsContract.Document;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8778f11..2245b16 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -20,14 +20,13 @@
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
-import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
-
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.BaseActivity.State.MODE_GRID;
+import static com.android.documentsui.BaseActivity.State.MODE_LIST;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -46,15 +45,12 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.util.Log;
-import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -79,7 +75,6 @@
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Maps;
import libcore.io.IoUtils;
@@ -87,11 +82,10 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
-public class DocumentsActivity extends Activity {
+public class DocumentsActivity extends BaseActivity {
public static final String TAG = "Documents";
private static final String EXTRA_STATE = "state";
@@ -203,8 +197,8 @@
moreApps.setComponent(null);
moreApps.setPackage(null);
RootsFragment.show(getFragmentManager(), moreApps);
- } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE
- || mState.action == ACTION_OPEN_TREE) {
+ } else if (mState.action == ACTION_OPEN
+ || mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) {
RootsFragment.show(getFragmentManager(), null);
}
@@ -389,6 +383,7 @@
updateActionBar();
}
+ @Override
public void setRootsDrawerOpen(boolean open) {
if (!mShowAsDialog) {
if (open) {
@@ -667,9 +662,7 @@
invalidateOptionsMenu();
}
- /**
- * Update UI to reflect internal state changes not from user.
- */
+ @Override
public void onStateChanged() {
invalidateOptionsMenu();
}
@@ -690,6 +683,7 @@
DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
}
+ @Override
public void setPending(boolean pending) {
final SaveFragment save = SaveFragment.get(getFragmentManager());
if (save != null) {
@@ -808,6 +802,7 @@
}
};
+ @Override
public RootInfo getCurrentRoot() {
if (mState.stack.root != null) {
return mState.stack.root;
@@ -816,6 +811,7 @@
}
}
+ @Override
public DocumentInfo getCurrentDirectory() {
return mState.stack.peek();
}
@@ -834,6 +830,7 @@
}
}
+ @Override
public State getDisplayState() {
return mState;
}
@@ -895,6 +892,7 @@
dumpStack();
}
+ @Override
public void onStackPicked(DocumentStack stack) {
try {
// Update the restored stack to ensure we have freshest data
@@ -909,6 +907,7 @@
}
}
+ @Override
public void onRootPicked(RootInfo root, boolean closeDrawer) {
// Clear entire backstack and start in new root
mState.stack.root = root;
@@ -955,6 +954,7 @@
}
}
+ @Override
public void onAppPicked(ResolveInfo info) {
final Intent intent = new Intent(getIntent());
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -985,6 +985,7 @@
}
}
+ @Override
public void onDocumentPicked(DocumentInfo doc) {
final FragmentManager fm = getFragmentManager();
if (doc.isDirectory()) {
@@ -1020,6 +1021,7 @@
}
}
+ @Override
public void onDocumentsPicked(List<DocumentInfo> docs) {
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
final int size = docs.size();
@@ -1031,14 +1033,17 @@
}
}
+ @Override
public void onSaveRequested(DocumentInfo replaceTarget) {
new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
}
+ @Override
public void onSaveRequested(String mimeType, String displayName) {
new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
}
+ @Override
public void onPickRequested(DocumentInfo pickTarget) {
final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
pickTarget.documentId);
@@ -1188,102 +1193,6 @@
}
}
- public static class State implements android.os.Parcelable {
- public int action;
- public String[] acceptMimes;
-
- /** Explicit user choice */
- public int userMode = MODE_UNKNOWN;
- /** Derived after loader */
- public int derivedMode = MODE_LIST;
-
- /** Explicit user choice */
- public int userSortOrder = SORT_ORDER_UNKNOWN;
- /** Derived after loader */
- public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
- public boolean allowMultiple = false;
- public boolean showSize = false;
- public boolean localOnly = false;
- public boolean forceAdvanced = false;
- public boolean showAdvanced = false;
- public boolean stackTouched = false;
- public boolean restored = false;
-
- /** Current user navigation stack; empty implies recents. */
- public DocumentStack stack = new DocumentStack();
- /** Currently active search, overriding any stack. */
- public String currentSearch;
-
- /** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
-
- public static final int ACTION_OPEN = 1;
- public static final int ACTION_CREATE = 2;
- public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_OPEN_TREE = 4;
- public static final int ACTION_MANAGE = 5;
-
- public static final int MODE_UNKNOWN = 0;
- public static final int MODE_LIST = 1;
- public static final int MODE_GRID = 2;
-
- public static final int SORT_ORDER_UNKNOWN = 0;
- public static final int SORT_ORDER_DISPLAY_NAME = 1;
- public static final int SORT_ORDER_LAST_MODIFIED = 2;
- public static final int SORT_ORDER_SIZE = 3;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(action);
- out.writeInt(userMode);
- out.writeStringArray(acceptMimes);
- out.writeInt(userSortOrder);
- out.writeInt(allowMultiple ? 1 : 0);
- out.writeInt(showSize ? 1 : 0);
- out.writeInt(localOnly ? 1 : 0);
- out.writeInt(forceAdvanced ? 1 : 0);
- out.writeInt(showAdvanced ? 1 : 0);
- out.writeInt(stackTouched ? 1 : 0);
- out.writeInt(restored ? 1 : 0);
- DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
- out.writeMap(dirState);
- }
-
- public static final Creator<State> CREATOR = new Creator<State>() {
- @Override
- public State createFromParcel(Parcel in) {
- final State state = new State();
- state.action = in.readInt();
- state.userMode = in.readInt();
- state.acceptMimes = in.readStringArray();
- state.userSortOrder = in.readInt();
- state.allowMultiple = in.readInt() != 0;
- state.showSize = in.readInt() != 0;
- state.localOnly = in.readInt() != 0;
- state.forceAdvanced = in.readInt() != 0;
- state.showAdvanced = in.readInt() != 0;
- state.stackTouched = in.readInt() != 0;
- state.restored = in.readInt() != 0;
- DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
- in.readMap(state.dirState, null);
- return state;
- }
-
- @Override
- public State[] newArray(int size) {
- return new State[size];
- }
- };
- }
-
private void dumpStack() {
Log.d(TAG, "Current stack: ");
Log.d(TAG, " * " + mState.stack.root);
@@ -1291,8 +1200,4 @@
Log.d(TAG, " +-- " + doc);
}
}
-
- public static DocumentsActivity get(Fragment fragment) {
- return (DocumentsActivity) fragment.getActivity();
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5112c92..4b008ca 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -69,7 +69,7 @@
private View.OnClickListener mPickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- final DocumentsActivity activity = DocumentsActivity.get(PickFragment.this);
+ final BaseActivity activity = BaseActivity.get(PickFragment.this);
activity.onPickRequested(mPickTarget);
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 34ce42d..f5908c5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -17,7 +17,7 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -34,7 +34,7 @@
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.android.collect.Maps;
import com.google.common.collect.Lists;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index dd75dbd..26aecc5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -45,7 +45,7 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -95,7 +95,7 @@
mListView.setAdapter(mAdapter);
final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final State state = ((DocumentsActivity) getActivity()).getDisplayState();
+ final State state = ((BaseActivity) getActivity()).getDisplayState();
mCallbacks = new LoaderCallbacks<List<DocumentStack>>() {
@Override
@@ -110,7 +110,7 @@
// When launched into empty recents, show drawer
if (mAdapter.isEmpty() && !state.stackTouched) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
+ ((BaseActivity) context).setRootsDrawerOpen(true);
}
}
@@ -139,7 +139,7 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final DocumentStack stack = mAdapter.getItem(position);
- ((DocumentsActivity) getActivity()).onStackPicked(stack);
+ ((BaseActivity) getActivity()).onStackPicked(stack);
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index d72db1d..ec71a04 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -36,7 +36,7 @@
import android.provider.DocumentsContract.Root;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 884cf31..ed5e123 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
-
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -43,7 +41,7 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import com.google.common.collect.Lists;
@@ -101,7 +99,7 @@
final Context context = getActivity();
final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final State state = ((DocumentsActivity) context).getDisplayState();
+ final State state = ((BaseActivity) context).getDisplayState();
mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
@Override
@@ -138,9 +136,9 @@
public void onDisplayStateChanged() {
final Context context = getActivity();
- final State state = ((DocumentsActivity) context).getDisplayState();
+ final State state = ((BaseActivity) context).getDisplayState();
- if (state.action == ACTION_GET_CONTENT) {
+ if (state.action == State.ACTION_GET_CONTENT) {
mList.setOnItemLongClickListener(mItemLongClickListener);
} else {
mList.setOnItemLongClickListener(null);
@@ -153,7 +151,7 @@
public void onCurrentRootChanged() {
if (mAdapter == null) return;
- final RootInfo root = ((DocumentsActivity) getActivity()).getCurrentRoot();
+ final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
for (int i = 0; i < mAdapter.getCount(); i++) {
final Object item = mAdapter.getItem(i);
if (item instanceof RootItem) {
@@ -176,7 +174,7 @@
private OnItemClickListener mItemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
+ final BaseActivity activity = BaseActivity.get(RootsFragment.this);
final Item item = mAdapter.getItem(position);
if (item instanceof RootItem) {
activity.onRootPicked(((RootItem) item).root, true);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 8d37cdf..49651b4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,7 @@
import android.content.AsyncTaskLoader;
import android.content.Context;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index ce98db2..a13fccc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -113,7 +113,7 @@
private View.OnClickListener mSaveListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
+ final BaseActivity activity = BaseActivity.get(SaveFragment.this);
if (mReplaceTarget != null) {
activity.onSaveRequested(mReplaceTarget);
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 6c8ca20..3ec3d1c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
new file mode 100644
index 0000000..e01328d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2015 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.documentsui;
+
+
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
+import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
+import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Debug;
+import android.provider.DocumentsContract;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SearchView.OnQueryTextListener;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.Toolbar;
+
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class StandaloneActivity extends BaseActivity {
+ public static final String TAG = "StandaloneFileManagement";
+
+ private static final String EXTRA_STATE = "state";
+
+ private static final int CODE_FORWARD = 42;
+
+ private SearchView mSearchView;
+
+ private Toolbar mToolbar;
+ private Spinner mToolbarStack;
+
+ private Toolbar mRootsToolbar;
+
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private DirectoryContainerView mDirectoryContainer;
+
+ private boolean mIgnoreNextNavigation;
+ private boolean mIgnoreNextClose;
+ private boolean mIgnoreNextCollapse;
+
+ private boolean mSearchExpanded;
+
+ private RootsCache mRoots;
+ private State mState;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ // Debug.waitForDebugger();
+ super.onCreate(icicle);
+
+ mRoots = DocumentsApplication.getRootsCache(this);
+
+ setResult(Activity.RESULT_CANCELED);
+ setContentView(R.layout.activity);
+
+ final Context context = this;
+ final Resources res = getResources();
+
+ // Strongly define our horizontal dimension; we leave vertical as
+ final WindowManager.LayoutParams a = getWindow().getAttributes();
+
+ final Point size = new Point();
+ getWindowManager().getDefaultDisplay().getSize(size);
+ // a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
+
+ getWindow().setAttributes(a);
+
+ mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
+
+ if (icicle != null) {
+ mState = icicle.getParcelable(EXTRA_STATE);
+ } else {
+ buildDefaultState();
+ }
+
+ mToolbar = (Toolbar) findViewById(R.id.toolbar);
+ mToolbar.setTitleTextAppearance(context,
+ android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+
+ mToolbarStack = (Spinner) findViewById(R.id.stack);
+ mToolbarStack.setOnItemSelectedListener(mStackListener);
+
+ mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
+ if (mRootsToolbar != null) {
+ mRootsToolbar.setTitleTextAppearance(context,
+ android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+ }
+
+ setActionBar(mToolbar);
+
+ RootsFragment.show(getFragmentManager(), null);
+ if (!mState.restored) {
+ new RestoreStackTask().execute();
+ } else {
+ onCurrentDirectoryChanged(ANIM_NONE);
+ }
+ }
+
+ private void buildDefaultState() {
+ mState = new State();
+
+ final Intent intent = getIntent();
+ mState.action = State.ACTION_MANAGE_ALL;
+ mState.acceptMimes = new String[] { "*/*" };
+ mState.allowMultiple = true;
+ mState.acceptMimes = new String[] { intent.getType() };
+ mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+ mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+ mState.showAdvanced = mState.forceAdvanced
+ | LocalPreferences.getDisplayAdvancedDevices(this);
+ mState.showSize = true;
+ }
+
+ private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
+ private Uri mRootUri;
+
+ public RestoreRootTask(Uri rootUri) {
+ mRootUri = rootUri;
+ }
+
+ @Override
+ protected RootInfo doInBackground(Void... params) {
+ final String rootId = DocumentsContract.getRootId(mRootUri);
+ return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+ }
+
+ @Override
+ protected void onPostExecute(RootInfo root) {
+ if (isDestroyed()) return;
+ mState.restored = true;
+
+ if (root != null) {
+ onRootPicked(root, true);
+ } else {
+ Log.w(TAG, "Failed to find root: " + mRootUri);
+ finish();
+ }
+ }
+ }
+
+ private class RestoreStackTask extends AsyncTask<Void, Void, Void> {
+ private volatile boolean mRestoredStack;
+ private volatile boolean mExternal;
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ // Restore last stack for calling package
+ final String packageName = getCallingPackageMaybeExtra();
+ final Cursor cursor = getContentResolver()
+ .query(RecentsProvider.buildResume(packageName), null, null, null, null);
+ try {
+ if (cursor.moveToFirst()) {
+ mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(ResumeColumns.STACK));
+ DurableUtils.readFromArray(rawStack, mState.stack);
+ mRestoredStack = true;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to resume: " + e);
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ if (mRestoredStack) {
+ // Update the restored stack to ensure we have freshest data
+ final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
+ try {
+ mState.stack.updateRoot(matchingRoots);
+ mState.stack.updateDocuments(getContentResolver());
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to restore stack: " + e);
+ mState.stack.reset();
+ mRestoredStack = false;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (isDestroyed()) return;
+ mState.restored = true;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ }
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ if (mDrawerToggle != null) {
+ mDrawerToggle.syncState();
+ }
+ updateActionBar();
+ }
+
+ @Override
+ public void setRootsDrawerOpen(boolean open) {
+ Log.w(TAG, "Trying to change state of roots drawer to > " + (open ? "open" : "closed"));
+ // throw new UnsupportedOperationException();
+ }
+
+ public void updateActionBar() {
+ final RootInfo root = getCurrentRoot();
+ mToolbar.setNavigationIcon(
+ root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
+ mToolbar.setNavigationContentDescription(R.string.drawer_open);
+ mToolbar.setNavigationOnClickListener(null);
+
+ if (mSearchExpanded) {
+ mToolbar.setTitle(null);
+ mToolbarStack.setVisibility(View.GONE);
+ mToolbarStack.setAdapter(null);
+ } else {
+ if (mState.stack.size() <= 1) {
+ mToolbar.setTitle(root.title);
+ mToolbarStack.setVisibility(View.GONE);
+ mToolbarStack.setAdapter(null);
+ } else {
+ mToolbar.setTitle(null);
+ mToolbarStack.setVisibility(View.VISIBLE);
+ mToolbarStack.setAdapter(mStackAdapter);
+
+ mIgnoreNextNavigation = true;
+ mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.activity, menu);
+
+ for (int i = 0; i < menu.size(); i++) {
+ final MenuItem item = menu.getItem(i);
+ switch (item.getItemId()) {
+ case R.id.menu_advanced:
+ case R.id.menu_file_size:
+ break;
+ default:
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
+ final MenuItem searchMenu = menu.findItem(R.id.menu_search);
+ mSearchView = (SearchView) searchMenu.getActionView();
+ mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ mSearchExpanded = true;
+ mState.currentSearch = query;
+ mSearchView.clearFocus();
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ return false;
+ }
+ });
+
+ searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ mSearchExpanded = true;
+ updateActionBar();
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ mSearchExpanded = false;
+ if (mIgnoreNextCollapse) {
+ mIgnoreNextCollapse = false;
+ return true;
+ }
+
+ mState.currentSearch = null;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return true;
+ }
+ });
+
+ mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ mSearchExpanded = false;
+ if (mIgnoreNextClose) {
+ mIgnoreNextClose = false;
+ return false;
+ }
+
+ mState.currentSearch = null;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return false;
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ final FragmentManager fm = getFragmentManager();
+
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
+ final MenuItem search = menu.findItem(R.id.menu_search);
+ final MenuItem sort = menu.findItem(R.id.menu_sort);
+ final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
+ final MenuItem grid = menu.findItem(R.id.menu_grid);
+ final MenuItem list = menu.findItem(R.id.menu_list);
+ final MenuItem advanced = menu.findItem(R.id.menu_advanced);
+ final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
+
+ sort.setVisible(cwd != null);
+ grid.setVisible(mState.derivedMode != State.MODE_GRID);
+ list.setVisible(mState.derivedMode != State.MODE_LIST);
+
+ if (mState.currentSearch != null) {
+ // Search uses backend ranking; no sorting
+ sort.setVisible(false);
+
+ search.expandActionView();
+
+ mSearchView.setIconified(false);
+ mSearchView.clearFocus();
+ mSearchView.setQuery(mState.currentSearch, false);
+ } else {
+ mIgnoreNextClose = true;
+ mSearchView.setIconified(true);
+ mSearchView.clearFocus();
+
+ mIgnoreNextCollapse = true;
+ search.collapseActionView();
+ }
+
+ // Only sort by size when visible
+ sortSize.setVisible(mState.showSize);
+
+ fileSize.setVisible(true);
+ search.setVisible(true);
+ createDir.setVisible(true);
+ advanced.setVisible(true);
+
+ advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
+ ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
+ fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
+ ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
+
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ final int id = item.getItemId();
+ if (id == android.R.id.home) {
+ onBackPressed();
+ return true;
+ } else if (id == R.id.menu_create_dir) {
+ CreateDirectoryFragment.show(getFragmentManager());
+ return true;
+ } else if (id == R.id.menu_search) {
+ return false;
+ } else if (id == R.id.menu_sort_name) {
+ setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
+ return true;
+ } else if (id == R.id.menu_sort_date) {
+ setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
+ return true;
+ } else if (id == R.id.menu_sort_size) {
+ setUserSortOrder(State.SORT_ORDER_SIZE);
+ return true;
+ } else if (id == R.id.menu_grid) {
+ setUserMode(State.MODE_GRID);
+ return true;
+ } else if (id == R.id.menu_list) {
+ setUserMode(State.MODE_LIST);
+ return true;
+ } else if (id == R.id.menu_advanced) {
+ setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
+ return true;
+ } else if (id == R.id.menu_file_size) {
+ setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void setDisplayAdvancedDevices(boolean display) {
+ LocalPreferences.setDisplayAdvancedDevices(this, display);
+ mState.showAdvanced = mState.forceAdvanced | display;
+ RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
+ invalidateOptionsMenu();
+ }
+
+ private void setDisplayFileSize(boolean display) {
+ LocalPreferences.setDisplayFileSize(this, display);
+ mState.showSize = display;
+ DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged();
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onStateChanged() {
+ invalidateOptionsMenu();
+ }
+
+ /**
+ * Set state sort order based on explicit user action.
+ */
+ private void setUserSortOrder(int sortOrder) {
+ mState.userSortOrder = sortOrder;
+ DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+ }
+
+ /**
+ * Set state mode based on explicit user action.
+ */
+ private void setUserMode(int mode) {
+ mState.userMode = mode;
+ DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+ }
+
+ @Override
+ public void setPending(boolean pending) {
+ final SaveFragment save = SaveFragment.get(getFragmentManager());
+ if (save != null) {
+ save.setPending(pending);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (!mState.stackTouched) {
+ super.onBackPressed();
+ return;
+ }
+
+ final int size = mState.stack.size();
+ if (size > 1) {
+ mState.stack.pop();
+ onCurrentDirectoryChanged(ANIM_UP);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle state) {
+ super.onSaveInstanceState(state);
+ state.putParcelable(EXTRA_STATE, mState);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ }
+
+ private BaseAdapter mStackAdapter = new BaseAdapter() {
+ @Override
+ public int getCount() {
+ return mState.stack.size();
+ }
+
+ @Override
+ public DocumentInfo getItem(int position) {
+ return mState.stack.get(mState.stack.size() - position - 1);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_subdir_title, parent, false);
+ }
+
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final DocumentInfo doc = getItem(position);
+
+ if (position == 0) {
+ final RootInfo root = getCurrentRoot();
+ title.setText(root.title);
+ } else {
+ title.setText(doc.displayName);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_subdir, parent, false);
+ }
+
+ final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final DocumentInfo doc = getItem(position);
+
+ if (position == 0) {
+ final RootInfo root = getCurrentRoot();
+ title.setText(root.title);
+ subdir.setVisibility(View.GONE);
+ } else {
+ title.setText(doc.displayName);
+ subdir.setVisibility(View.VISIBLE);
+ }
+
+ return convertView;
+ }
+ };
+
+ private OnItemSelectedListener mStackListener = new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (mIgnoreNextNavigation) {
+ mIgnoreNextNavigation = false;
+ return;
+ }
+
+ while (mState.stack.size() > position + 1) {
+ mState.stackTouched = true;
+ mState.stack.pop();
+ }
+ onCurrentDirectoryChanged(ANIM_UP);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Ignored
+ }
+ };
+
+ @Override
+ public RootInfo getCurrentRoot() {
+ if (mState.stack.root != null) {
+ return mState.stack.root;
+ } else {
+ return mRoots.getRecentsRoot();
+ }
+ }
+
+ public DocumentInfo getCurrentDirectory() {
+ return mState.stack.peek();
+ }
+
+ private String getCallingPackageMaybeExtra() {
+ final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME);
+ return (extra != null) ? extra : getCallingPackage();
+ }
+
+ public Executor getCurrentExecutor() {
+ final DocumentInfo cwd = getCurrentDirectory();
+ if (cwd != null && cwd.authority != null) {
+ return ProviderExecutor.forAuthority(cwd.authority);
+ } else {
+ return AsyncTask.THREAD_POOL_EXECUTOR;
+ }
+ }
+
+ @Override
+ public State getDisplayState() {
+ return mState;
+ }
+
+ private void onCurrentDirectoryChanged(int anim) {
+ final FragmentManager fm = getFragmentManager();
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
+
+ if (cwd == null) {
+ DirectoryFragment.showRecentsOpen(fm, anim);
+
+ // Start recents in grid when requesting visual things
+ final boolean visualMimes = MimePredicate.mimeMatches(
+ MimePredicate.VISUAL_MIMES, mState.acceptMimes);
+ mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
+ mState.derivedMode = mState.userMode;
+ } else {
+ if (mState.currentSearch != null) {
+ // Ongoing search
+ DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
+ } else {
+ // Normal boring directory
+ DirectoryFragment.showNormal(fm, root, cwd, anim);
+ }
+ }
+
+ final RootsFragment roots = RootsFragment.get(fm);
+ if (roots != null) {
+ roots.onCurrentRootChanged();
+ }
+
+ updateActionBar();
+ invalidateOptionsMenu();
+ dumpStack();
+ }
+
+ @Override
+ public void onStackPicked(DocumentStack stack) {
+ try {
+ // Update the restored stack to ensure we have freshest data
+ stack.updateDocuments(getContentResolver());
+
+ mState.stack = stack;
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_SIDE);
+
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to restore stack: " + e);
+ }
+ }
+
+ @Override
+ public void onRootPicked(RootInfo root, boolean closeDrawer) {
+ // Clear entire backstack and start in new root
+ mState.stack.root = root;
+ mState.stack.clear();
+ mState.stackTouched = true;
+
+ if (!mRoots.isRecentsRoot(root)) {
+ new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
+ } else {
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ }
+ }
+
+ private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
+ private RootInfo mRoot;
+
+ public PickRootTask(RootInfo root) {
+ mRoot = root;
+ }
+
+ @Override
+ protected DocumentInfo doInBackground(Void... params) {
+ try {
+ final Uri uri = DocumentsContract.buildDocumentUri(
+ mRoot.authority, mRoot.documentId);
+ return DocumentInfo.fromUri(getContentResolver(), uri);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to find root", e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(DocumentInfo result) {
+ if (result != null) {
+ mState.stack.push(result);
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ }
+ }
+ }
+
+ @Override
+ public void onAppPicked(ResolveInfo info) {
+ final Intent intent = new Intent(getIntent());
+ intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ intent.setComponent(new ComponentName(
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
+ startActivityForResult(intent, CODE_FORWARD);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ Log.d(TAG, "onActivityResult() code=" + resultCode);
+
+ // Only relay back results when not canceled; otherwise stick around to
+ // let the user pick another app/backend.
+ if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) {
+
+ // Remember that we last picked via external app
+ final String packageName = getCallingPackageMaybeExtra();
+ final ContentValues values = new ContentValues();
+ values.put(ResumeColumns.EXTERNAL, 1);
+ getContentResolver().insert(RecentsProvider.buildResume(packageName), values);
+
+ // Pass back result to original caller
+ setResult(resultCode, data);
+ finish();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ @Override
+ public void onDocumentPicked(DocumentInfo doc) {
+ final FragmentManager fm = getFragmentManager();
+ if (doc.isDirectory()) {
+ mState.stack.push(doc);
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_DOWN);
+ } else {
+ // Fall back to viewing
+ final Intent view = new Intent(Intent.ACTION_VIEW);
+ view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ view.setData(doc.derivedUri);
+
+ try {
+ startActivity(view);
+ } catch (ActivityNotFoundException ex2) {
+ Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ public void onDocumentsPicked(List<DocumentInfo> docs) {
+ // TODO
+ }
+
+ @Override
+ public void onSaveRequested(DocumentInfo replaceTarget) {
+ new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
+ }
+
+ @Override
+ public void onSaveRequested(String mimeType, String displayName) {
+ new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
+ }
+
+ @Override
+ public void onPickRequested(DocumentInfo pickTarget) {
+ final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
+ pickTarget.documentId);
+ new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor());
+ }
+
+ private void saveStackBlocking() {
+ final ContentResolver resolver = getContentResolver();
+ final ContentValues values = new ContentValues();
+
+ final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
+
+ // Remember location for next app launch
+ final String packageName = getCallingPackageMaybeExtra();
+ values.clear();
+ values.put(ResumeColumns.STACK, rawStack);
+ values.put(ResumeColumns.EXTERNAL, 0);
+ resolver.insert(RecentsProvider.buildResume(packageName), values);
+ }
+
+ private void onFinished(Uri... uris) {
+ Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+
+ final Intent intent = new Intent();
+ if (uris.length == 1) {
+ intent.setData(uris[0]);
+ } else if (uris.length > 1) {
+ final ClipData clipData = new ClipData(
+ null, mState.acceptMimes, new ClipData.Item(uris[0]));
+ for (int i = 1; i < uris.length; i++) {
+ clipData.addItem(new ClipData.Item(uris[i]));
+ }
+ intent.setClipData(clipData);
+ }
+
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ private class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
+ private final String mMimeType;
+ private final String mDisplayName;
+
+ public CreateFinishTask(String mimeType, String displayName) {
+ mMimeType = mimeType;
+ mDisplayName = displayName;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ setPending(true);
+ }
+
+ @Override
+ protected Uri doInBackground(Void... params) {
+ final ContentResolver resolver = getContentResolver();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ ContentProviderClient client = null;
+ Uri childUri = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ resolver, cwd.derivedUri.getAuthority());
+ childUri = DocumentsContract.createDocument(
+ client, cwd.derivedUri, mMimeType, mDisplayName);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to create document", e);
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+
+ if (childUri != null) {
+ saveStackBlocking();
+ }
+
+ return childUri;
+ }
+
+ @Override
+ protected void onPostExecute(Uri result) {
+ if (result != null) {
+ onFinished(result);
+ } else {
+ Toast.makeText(StandaloneActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ setPending(false);
+ }
+ }
+
+ private class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri[] mUris;
+
+ public ExistingFinishTask(Uri... uris) {
+ mUris = uris;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUris);
+ }
+ }
+
+ private class PickFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri mUri;
+
+ public PickFinishTask(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUri);
+ }
+ }
+
+ private void dumpStack() {
+ Log.d(TAG, "Current stack: ");
+ Log.d(TAG, " * " + mState.stack.root);
+ for (DocumentInfo doc : mState.stack) {
+ Log.d(TAG, " +-- " + doc);
+ }
+ }
+
+ public static BaseActivity get(Fragment fragment) {
+ return (BaseActivity) fragment.getActivity();
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5fa0dd1..c9805ae 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -40,6 +40,7 @@
import android.media.AudioManager;
import android.os.BatteryManager;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
@@ -51,9 +52,11 @@
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.FingerprintManager.AuthenticationResult;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -109,10 +112,11 @@
private static final int MSG_SCREEN_TURNED_ON = 319;
private static final int MSG_SCREEN_TURNED_OFF = 320;
private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
- private static final int MSG_FINGERPRINT_PROCESSED = 323;
- private static final int MSG_FINGERPRINT_ACQUIRED = 324;
- private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325;
- private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326;
+ private static final int MSG_FINGERPRINT_AUTHENTICATED = 323;
+ private static final int MSG_FINGERPRINT_ERROR = 324;
+ private static final int MSG_FINGERPRINT_HELP = 325;
+ private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 326;
+ private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 327;
private static KeyguardUpdateMonitor sInstance;
@@ -201,11 +205,14 @@
case MSG_SCREEN_TURNED_ON:
handleScreenTurnedOn();
break;
- case MSG_FINGERPRINT_ACQUIRED:
- handleFingerprintAcquired(msg.arg1);
+ case MSG_FINGERPRINT_AUTHENTICATED:
+ handleFingerprintAuthenticated(msg.arg1, msg.arg2);
break;
- case MSG_FINGERPRINT_PROCESSED:
- handleFingerprintProcessed(msg.arg1);
+ case MSG_FINGERPRINT_HELP:
+ handleFingerprintHelp(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
+ break;
+ case MSG_FINGERPRINT_ERROR:
+ handleFingerprintError(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
break;
case MSG_FACE_UNLOCK_STATE_CHANGED:
handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
@@ -227,7 +234,7 @@
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
- private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
+ private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
@Override
@@ -314,18 +321,18 @@
}
}
- private void onFingerprintRecognized(int userId) {
- mUserFingerprintRecognized.put(userId, true);
+ private void onFingerprintAuthenticated(int userId) {
+ mUserFingerprintAuthenticated.put(userId, true);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintRecognized(userId);
+ cb.onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintProcessed(int fingerprintId) {
- if (fingerprintId == 0) return; // not a valid fingerprint
+ private void handleFingerprintAuthenticated(int fingerId, int groupId) {
+ if (fingerId == 0) return; // not a valid fingerprint
final int userId;
try {
@@ -341,17 +348,28 @@
final ContentResolver res = mContext.getContentResolver();
final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
for (int i = 0; i < ids.length; i++) {
- if (ids[i] == fingerprintId) {
- onFingerprintRecognized(userId);
+ // TODO: fix once HAL supports storing group id
+ final boolean isCorrectUser = true || (groupId == userId);
+ if (ids[i] == fingerId && isCorrectUser) {
+ onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintAcquired(int info) {
+ private void handleFingerprintHelp(int msgId, String helpString) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAcquired(info);
+ cb.onFingerprintHelp(msgId, helpString);
+ }
+ }
+ }
+
+ private void handleFingerprintError(int msgId, String errString) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFingerprintError(msgId, errString);
}
}
}
@@ -387,7 +405,7 @@
public boolean getUserHasTrust(int userId) {
return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
- || mUserFingerprintRecognized.get(userId);
+ || mUserFingerprintAuthenticated.get(userId);
}
public boolean getUserTrustIsManaged(int userId) {
@@ -464,23 +482,29 @@
}
}
};
- private FingerprintManagerReceiver mFingerprintManagerReceiver =
- new FingerprintManagerReceiver() {
- @Override
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
- };
+
+ private FingerprintManager.AuthenticationCallback mAuthenticationCallback
+ = new AuthenticationCallback() {
@Override
- public void onAcquired(int info) {
- mHandler.obtainMessage(MSG_FINGERPRINT_ACQUIRED, info, 0).sendToTarget();
+ public void onAuthenticationSucceeded(AuthenticationResult result) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED,
+ result.getFingerprint().getFingerId(),
+ result.getFingerprint().getGroupId()).sendToTarget();
}
@Override
- public void onError(int error) {
- if (DEBUG) Log.w(TAG, "FingerprintManager reported error: " + error);
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_HELP, helpMsgId, 0, helpString).sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString);
}
};
+ private CancellationSignal mFingerprintCancelSignal;
+ private FingerprintManager mFpm;
/**
* When we receive a
@@ -606,6 +630,7 @@
cb.onScreenTurnedOn();
}
}
+ startListeningForFingerprint(mContext);
}
protected void handleScreenTurnedOff(int arg1) {
@@ -617,6 +642,7 @@
cb.onScreenTurnedOff(arg1);
}
}
+ stopListeningForFingerprint();
}
/**
@@ -705,9 +731,25 @@
TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
trustManager.registerTrustListener(this);
- FingerprintManager fpm;
- fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
- fpm.startListening(mFingerprintManagerReceiver);
+ mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+ startListeningForFingerprint(context);
+ }
+
+ private void startListeningForFingerprint(Context context) {
+ if (mFpm != null && mFpm.isHardwareDetected()) {
+ if (mFingerprintCancelSignal == null) {
+ mFingerprintCancelSignal = new CancellationSignal();
+ } else {
+ mFingerprintCancelSignal.cancel();
+ }
+ mFpm.authenticate(null, mAuthenticationCallback, mFingerprintCancelSignal, 0);
+ }
+ }
+
+ private void stopListeningForFingerprint() {
+ if (mFingerprintCancelSignal != null) {
+ mFingerprintCancelSignal.cancel();
+ }
}
private boolean isDeviceProvisionedInSettingsDb() {
@@ -1152,7 +1194,7 @@
}
public void clearFingerprintRecognized() {
- mUserFingerprintRecognized.clear();
+ mUserFingerprintAuthenticated.clear();
}
public void reportFailedUnlockAttempt() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index f0e2389..c2462e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.SystemClock;
+import android.service.fingerprint.FingerprintManager;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicy;
@@ -176,14 +177,24 @@
/**
* Called when a fingerprint is recognized.
- * @param userId
+ * @param userId the user id for which the fingerprint was authenticated
*/
- public void onFingerprintRecognized(int userId) { }
+ public void onFingerprintAuthenticated(int userId) { }
/**
- * Called when fingerprint is acquired but not yet recognized
+ * Called when fingerprint provides help string (e.g. "Try again")
+ * @param msgId
+ * @param helpString
*/
- public void onFingerprintAcquired(int info) { }
+ public void onFingerprintHelp(int msgId, String helpString) { }
+
+ /**
+ * Called when fingerprint provides an semi-permanent error message
+ * (e.g. "Hardware not available").
+ * @param msgId one of the error messages listed in {@link FingerprintManager}
+ * @param errString
+ */
+ public void onFingerprintError(int msgId, String errString) { }
/**
* Called when the state of face unlock changed.
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
new file mode 100644
index 0000000..cea6324
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM4.0,10.0l10.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
new file mode 100644
index 0000000..c2ae9c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,20.0L10.0,20.0L10.0,10.0l10.0,0.0L20.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
new file mode 100644
index 0000000..feb612c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,4.0l10.0,0.0l0.0,10.0L4.0,14.0L4.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
new file mode 100644
index 0000000..9f4ee49
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM20.0,14.0L10.0,14.0L10.0,4.0l10.0,0.0L20.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
similarity index 77%
rename from packages/SystemUI/res/layout/recents_task_resize_dialog.xml
rename to packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
index a8c6ee9..a718d4d 100644
--- a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
@@ -41,20 +41,6 @@
android:layout_margin="10dp"
android:background="@drawable/vector_drawable_place_right" />
<Button
- android:id="@+id/place_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top" />
- <Button
- android:id="@+id/place_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom" />
- <Button
android:id="@+id/place_full"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
similarity index 77%
copy from packages/SystemUI/res/layout/recents_task_resize_dialog.xml
copy to packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
index a8c6ee9..250f53d 100644
--- a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
@@ -27,20 +27,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
- android:id="@+id/place_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_left" />
- <Button
- android:id="@+id/place_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_right" />
- <Button
android:id="@+id/place_top"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
similarity index 68%
copy from packages/SystemUI/res/layout/recents_task_resize_dialog.xml
copy to packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
index a8c6ee9..29e4bce 100644
--- a/packages/SystemUI/res/layout/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
@@ -55,6 +55,34 @@
android:layout_margin="10dp"
android:background="@drawable/vector_drawable_place_bottom" />
<Button
+ android:id="@+id/place_top_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top_left" />
+ <Button
+ android:id="@+id/place_top_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top_right" />
+ <Button
+ android:id="@+id/place_bottom_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom_left" />
+ <Button
+ android:id="@+id/place_bottom_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom_right" />
+ <Button
android:id="@+id/place_full"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 49bdfda..dd28734 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -436,7 +436,8 @@
}
}
- public void onFingerprintRecognized(int userId) {
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mViewMediatorCallback.keyguardDone(true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 7c11894..4cd577d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -24,6 +24,7 @@
import android.content.DialogInterface;
import android.graphics.Rect;
import android.os.Bundle;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
@@ -34,6 +35,8 @@
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.views.RecentsView;
+import java.util.ArrayList;
+
/**
* A helper for the dialogs that show when task debugging is on.
*/
@@ -46,16 +49,32 @@
private static final int PLACE_RIGHT = 2;
private static final int PLACE_TOP = 3;
private static final int PLACE_BOTTOM = 4;
- private static final int PLACE_FULL = 5;
+ private static final int PLACE_TOP_LEFT = 5;
+ private static final int PLACE_TOP_RIGHT = 6;
+ private static final int PLACE_BOTTOM_LEFT = 7;
+ private static final int PLACE_BOTTOM_RIGHT = 8;
+ private static final int PLACE_FULL = 9;
+
+ // The button resource ID combined with the arrangement command.
+ private static final int[][] BUTTON_DEFINITIONS =
+ {{R.id.place_left, PLACE_LEFT},
+ {R.id.place_right, PLACE_RIGHT},
+ {R.id.place_top, PLACE_TOP},
+ {R.id.place_bottom, PLACE_BOTTOM},
+ {R.id.place_top_left, PLACE_TOP_LEFT},
+ {R.id.place_top_right, PLACE_TOP_RIGHT},
+ {R.id.place_bottom_left, PLACE_BOTTOM_LEFT},
+ {R.id.place_bottom_right, PLACE_BOTTOM_RIGHT},
+ {R.id.place_full, PLACE_FULL}};
// The task we want to resize.
- private Task mTaskToResize;
- private Task mNextTaskToResize;
private FragmentManager mFragmentManager;
private View mResizeTaskDialogContent;
private RecentsActivity mRecentsActivity;
private RecentsView mRecentsView;
private SystemServicesProxy mSsp;
+ private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
+ private Task[] mTasks = {null, null, null, null};
public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
mFragmentManager = mgr;
@@ -65,9 +84,8 @@
/** Shows the resize-task dialog. */
void showResizeTaskDialog(Task mainTask, RecentsView rv) {
- mTaskToResize = mainTask;
+ mTasks[0] = mainTask;
mRecentsView = rv;
- mNextTaskToResize = mRecentsView.getNextTaskOrTopTask(mainTask);
show(mFragmentManager, TAG);
}
@@ -79,36 +97,18 @@
mResizeTaskDialogContent =
inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
- ((Button)mResizeTaskDialogContent.findViewById(R.id.place_left)).setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- placeTasks(PLACE_LEFT);
+ for (int i = 0; i < BUTTON_DEFINITIONS.length; i++) {
+ Button b = (Button)mResizeTaskDialogContent.findViewById(BUTTON_DEFINITIONS[i][0]);
+ if (b != null) {
+ final int action = BUTTON_DEFINITIONS[i][1];
+ b.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ placeTasks(action);
+ }
+ });
}
- });
- ((Button)mResizeTaskDialogContent.findViewById(R.id.place_right)).setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- placeTasks(PLACE_RIGHT);
- }
- });
- ((Button)mResizeTaskDialogContent.findViewById(R.id.place_top)).setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- placeTasks(PLACE_TOP);
- }
- });
- ((Button)mResizeTaskDialogContent.findViewById(R.id.place_bottom)).setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- placeTasks(PLACE_BOTTOM);
- }
- });
- ((Button)mResizeTaskDialogContent.findViewById(R.id.place_full)).setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- placeTasks(PLACE_FULL);
- }
- });
+ }
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
@@ -122,48 +122,111 @@
/** Helper function to place window(s) on the display according to an arrangement request. */
private void placeTasks(int arrangement) {
- Rect focusedBounds = mSsp.getWindowRect();
- Rect otherBounds = new Rect(focusedBounds);
-
+ Rect rect = mSsp.getWindowRect();
+ for (int i = 0; i < mBounds.length; ++i) {
+ mBounds[i].set(rect);
+ if (i != 0) {
+ mTasks[i] = null;
+ }
+ }
+ int additionalTasks = 0;
switch (arrangement) {
case PLACE_LEFT:
- focusedBounds.right = focusedBounds.centerX();
- otherBounds.left = focusedBounds.right;
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[1].left = mBounds[0].right;
+ additionalTasks = 1;
break;
case PLACE_RIGHT:
- otherBounds.right = otherBounds.centerX();
- focusedBounds.left = otherBounds.right;
+ mBounds[1].right = mBounds[1].centerX();
+ mBounds[0].left = mBounds[1].right;
+ additionalTasks = 1;
break;
case PLACE_TOP:
- focusedBounds.bottom = focusedBounds.centerY();
- otherBounds.top = focusedBounds.bottom;
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].top = mBounds[0].bottom;
+ additionalTasks = 1;
break;
case PLACE_BOTTOM:
- otherBounds.bottom = otherBounds.centerY();
- focusedBounds.top = otherBounds.bottom;
+ mBounds[1].bottom = mBounds[1].centerY();
+ mBounds[0].top = mBounds[1].bottom;
+ additionalTasks = 1;
+ break;
+ case PLACE_TOP_LEFT: // TL, TR, BL, BR
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].left = mBounds[0].right;
+ mBounds[1].bottom = mBounds[0].bottom;
+ mBounds[2].right = mBounds[0].right;
+ mBounds[2].top = mBounds[0].bottom;
+ mBounds[3].left = mBounds[0].right;
+ mBounds[3].top = mBounds[0].bottom;
+ additionalTasks = 3;
+ break;
+ case PLACE_TOP_RIGHT: // TR, TL, BR, BL
+ mBounds[0].left = mBounds[0].centerX();
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].right = mBounds[0].left;
+ mBounds[1].bottom = mBounds[0].bottom;
+ mBounds[2].left = mBounds[0].left;
+ mBounds[2].top = mBounds[0].bottom;
+ mBounds[3].right = mBounds[0].left;
+ mBounds[3].top = mBounds[0].bottom;
+ additionalTasks = 3;
+ break;
+ case PLACE_BOTTOM_LEFT: // BL, BR, TL, TR
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[0].top = mBounds[0].centerY();
+ mBounds[1].left = mBounds[0].right;
+ mBounds[1].top = mBounds[0].top;
+ mBounds[2].right = mBounds[0].right;
+ mBounds[2].bottom = mBounds[0].top;
+ mBounds[3].left = mBounds[0].right;
+ mBounds[3].bottom = mBounds[0].top;
+ additionalTasks = 3;
+ break;
+ case PLACE_BOTTOM_RIGHT: // BR, BL, TR, TL
+ mBounds[0].left = mBounds[0].centerX();
+ mBounds[0].top = mBounds[0].centerY();
+ mBounds[1].right = mBounds[0].left;
+ mBounds[1].top = mBounds[0].top;
+ mBounds[2].left = mBounds[0].left;
+ mBounds[2].bottom = mBounds[0].top;
+ mBounds[3].right = mBounds[0].left;
+ mBounds[3].bottom = mBounds[0].top;
+ additionalTasks = 3;
break;
case PLACE_FULL:
- // Null the rectangle to avoid the other task to show up.
- otherBounds = new Rect();
+ // Nothing to change.
break;
}
- // Resize all other tasks to go to the other side.
- if (mNextTaskToResize != null && !otherBounds.isEmpty()) {
- mSsp.resizeTask(mNextTaskToResize.key.id, otherBounds);
+ // Get the other tasks.
+ for (int i = 1; i <= additionalTasks && mTasks[i - 1] != null; ++i) {
+ mTasks[i] = mRecentsView.getNextTaskOrTopTask(mTasks[i - 1]);
+ // Do stop if we circled back to the first item.
+ if (mTasks[i] == mTasks[0]) {
+ mTasks[i] = null;
+ }
}
- mSsp.resizeTask(mTaskToResize.key.id, focusedBounds);
+
+ // Resize all tasks beginning from the "oldest" one.
+ for (int i = additionalTasks; i >= 0; --i) {
+ if (mTasks[i] != null) {
+ mSsp.resizeTask(mTasks[i].key.id, mBounds[i]);
+ }
+ }
// Get rid of the dialog.
dismiss();
mRecentsActivity.dismissRecentsToHomeRaw(false);
- // Show tasks - beginning with the other first so that the focus ends on the selected one.
+ // Show tasks - beginning with the oldest so that the focus ends on the selected one.
// TODO: Remove this once issue b/19893373 is resolved.
- if (mNextTaskToResize != null && !otherBounds.isEmpty()) {
- mRecentsView.launchTask(mNextTaskToResize);
+ for (int i = additionalTasks; i >= 0; --i) {
+ if (mTasks[i] != null) {
+ mRecentsView.launchTask(mTasks[i]);
+ }
}
- mRecentsView.launchTask(mTaskToResize);
}
@Override
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 42399a3..60a91bf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -191,10 +191,7 @@
mApplicationIcon.setImageDrawable(t.applicationIcon);
}
mApplicationIcon.setContentDescription(t.activityLabel);
- // Always update when multi stack debugging is enabled as the stack id can change
- if (mConfig.multiStackEnabled) {
- mActivityDescription.setText("[" + t.key.stackId + "] " + t.activityLabel);
- } else if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
+ if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
mActivityDescription.setText(t.activityLabel);
}
// Try and apply the system ui tint
@@ -212,6 +209,9 @@
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
t.activityLabel));
mMoveTaskButton.setVisibility((mConfig.multiStackEnabled) ? View.VISIBLE : View.INVISIBLE);
+ if (mConfig.multiStackEnabled) {
+ updateResizeTaskBarIcon(t);
+ }
}
/** Updates the resize task bar button. */
@@ -219,7 +219,7 @@
Rect display = mSsp.getWindowRect();
Rect taskRect = mSsp.getTaskBounds(t.key.stackId);
int resId = R.drawable.star;
- if (display.equals(taskRect)) {
+ if (display.equals(taskRect) || taskRect.isEmpty()) {
resId = R.drawable.vector_drawable_place_fullscreen;
} else {
boolean top = display.top == taskRect.top;
@@ -234,6 +234,14 @@
resId = R.drawable.vector_drawable_place_top;
} else if (bottom && left && right) {
resId = R.drawable.vector_drawable_place_bottom;
+ } else if (top && right) {
+ resId = R.drawable.vector_drawable_place_top_right;
+ } else if (top && left) {
+ resId = R.drawable.vector_drawable_place_top_left;
+ } else if (bottom && right) {
+ resId = R.drawable.vector_drawable_place_bottom_right;
+ } else if (bottom && left) {
+ resId = R.drawable.vector_drawable_place_bottom_left;
}
}
mMoveTaskButton.setImageResource(resId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 5ef345b..65cd268 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -125,7 +125,7 @@
}
@Override
- public void onFingerprintRecognized(int userId) {
+ public void onFingerprintAuthenticated(int userId) {
update(false /* updateAlways */);
}
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 523c8fb..c4daaa9 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -802,7 +802,7 @@
/**
* This is only intended to be used by auto-generated code reflected from
- * the RenderScript script files.
+ * the RenderScript script files and should not be used by developers.
*
* @param xoff
* @param component_number
@@ -813,9 +813,8 @@
}
/**
- * @hide
* This is only intended to be used by auto-generated code reflected from
- * the RenderScript script files.
+ * the RenderScript script files and should not be used by developers.
*
* @param xoff
* @param yoff
@@ -1247,8 +1246,11 @@
}
/**
- * @hide
+ * Copy a rectangular region from the array into the allocation.
+ * The array is assumed to be tightly packed.
*
+ * The data type of the array is not required to be the same as
+ * the element data type.
*/
private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
Object array, Element.DataType dt, int arrayLen) {
@@ -1277,7 +1279,6 @@
}
/**
- * @hide
* Copy a rectangular region from the array into the allocation.
* The array is assumed to be tightly packed.
*
@@ -1298,7 +1299,6 @@
}
/**
- * @hide
* Copy a rectangular region into the allocation from another
* allocation.
*
@@ -1415,7 +1415,6 @@
}
/**
- * @hide
* This is only intended to be used by auto-generated code reflected from
* the RenderScript script files and should not be used by developers.
*
@@ -1423,7 +1422,7 @@
* @param yoff
* @param zoff
* @param component_number
- * @param array
+ * @param fp
*/
public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
mRS.validate();
@@ -1501,7 +1500,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1516,7 +1514,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1529,7 +1526,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1542,7 +1538,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1555,7 +1550,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1569,7 +1563,6 @@
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type does not
* match the component type of the array passed in.
@@ -1585,7 +1578,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit
* integer type.
@@ -1600,7 +1592,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 16 bit
* integer type.
@@ -1615,7 +1606,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not an 8 bit
* integer type.
@@ -1630,7 +1620,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit float
* type.
@@ -1671,7 +1660,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1687,7 +1675,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1703,7 +1690,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1719,7 +1705,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1735,7 +1720,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1752,8 +1736,11 @@
/**
- * @hide
+ * Copy from a rectangular region in this Allocation into an array.
+ * The array is assumed to be tightly packed.
*
+ * The data type of the array is not required to be the same as
+ * the element data type.
*/
private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
Object array, Element.DataType dt, int arrayLen) {
@@ -1780,8 +1767,7 @@
Trace.traceEnd(RenderScript.TRACE_TAG);
}
- /**
- * @hide
+ /*
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 287b3f1..60ff996 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -114,7 +114,8 @@
* MATRIX the three matrix types contain FLOAT_32 elements and are treated
* as 32 bits for alignment purposes.
*
- * RS_* objects. 32 bit opaque handles.
+ * RS_* objects: opaque handles with implementation dependent
+ * sizes.
*/
public enum DataType {
NONE (0, 0),
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 4164810..9d8f162 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -145,6 +145,9 @@
case MESH:
entry.mLoadedObj = new Mesh(objectID, rs);
break;
+
+ default:
+ throw new RSRuntimeException("Unrecognized object type in file.");
}
entry.mLoadedObj.updateFromNative();
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 5b4cadb..13c8e1c 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -363,6 +363,9 @@
alloc = Allocation.createTyped(mRS, entry.t, mUsage);
} else if(entry.e != null) {
alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+ } else {
+ // Should never happen because the builder will always set one
+ throw new IllegalStateException("Builder corrupt, no valid element in entry.");
}
vertexBuffers[ct] = alloc;
vtx[ct] = alloc.getID(mRS);
@@ -375,6 +378,9 @@
alloc = Allocation.createTyped(mRS, entry.t, mUsage);
} else if(entry.e != null) {
alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+ } else {
+ // Should never happen because the builder will always set one
+ throw new IllegalStateException("Builder corrupt, no valid element in entry.");
}
long allocID = (alloc == null) ? 0 : alloc.getID(mRS);
indexBuffers[ct] = alloc;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 78bd15d..b5e1de9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2188,7 +2188,7 @@
systemDir.mkdirs();
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
+ mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
@@ -2432,7 +2432,7 @@
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
- mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
+ mBatteryStatsService.scheduleWriteToDisk();
}
}
}
@@ -6326,31 +6326,38 @@
}
try {
PendingIntentRecord res = (PendingIntentRecord)pendingResult;
- Intent intent = res.key.requestIntent;
- if (intent != null) {
- if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
- || res.lastTagPrefix.equals(prefix))) {
- return res.lastTag;
- }
- res.lastTagPrefix = prefix;
- StringBuilder sb = new StringBuilder(128);
- if (prefix != null) {
- sb.append(prefix);
- }
- if (intent.getAction() != null) {
- sb.append(intent.getAction());
- } else if (intent.getComponent() != null) {
- intent.getComponent().appendShortString(sb);
- } else {
- sb.append("?");
- }
- return res.lastTag = sb.toString();
+ synchronized (this) {
+ return getTagForIntentSenderLocked(res, prefix);
}
} catch (ClassCastException e) {
}
return null;
}
+ String getTagForIntentSenderLocked(PendingIntentRecord res, String prefix) {
+ final Intent intent = res.key.requestIntent;
+ if (intent != null) {
+ if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
+ || res.lastTagPrefix.equals(prefix))) {
+ return res.lastTag;
+ }
+ res.lastTagPrefix = prefix;
+ final StringBuilder sb = new StringBuilder(128);
+ if (prefix != null) {
+ sb.append(prefix);
+ }
+ if (intent.getAction() != null) {
+ sb.append(intent.getAction());
+ } else if (intent.getComponent() != null) {
+ intent.getComponent().appendShortString(sb);
+ } else {
+ sb.append("?");
+ }
+ return res.lastTag = sb.toString();
+ }
+ return null;
+ }
+
@Override
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
@@ -10479,17 +10486,21 @@
if (!(sender instanceof PendingIntentRecord)) {
return;
}
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ final PendingIntentRecord rec = (PendingIntentRecord)sender;
+ final String tag;
+ synchronized (this) {
+ tag = getTagForIntentSenderLocked(rec, "*walarm*:");
+ }
+ final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
if (mBatteryStatsService.isOnBattery()) {
mBatteryStatsService.enforceCallingPermission();
- PendingIntentRecord rec = (PendingIntentRecord)sender;
int MY_UID = Binder.getCallingUid();
int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
BatteryStatsImpl.Uid.Pkg pkg =
stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
sourcePkg != null ? sourcePkg : rec.key.packageName);
- pkg.incWakeupsLocked();
+ pkg.noteWakeupAlarmLocked(tag);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f5fef63..066ff37 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3896,8 +3896,7 @@
return true;
}
- private boolean relaunchActivityLocked(ActivityRecord r,
- int changes, boolean andResume) {
+ private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index cb96680..f874244 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -273,8 +273,8 @@
* until the task exits or #stopLockTaskMode() is called. */
TaskRecord mLockTaskModeTask;
/** Store the current lock task mode. Possible values:
- * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
- * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
*/
private int mLockTaskModeState;
/**
@@ -1132,12 +1132,13 @@
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
- r.startFreezingScreenLocked(app, 0);
- if (false) Slog.d(TAG, "realStartActivity: setting app visibility true");
- mWindowManager.setAppVisibility(r.appToken, true);
+ if (andResume) {
+ r.startFreezingScreenLocked(app, 0);
+ mWindowManager.setAppVisibility(r.appToken, true);
- // schedule launch ticks to collect information about slow apps.
- r.startLaunchTickingLocked();
+ // schedule launch ticks to collect information about slow apps.
+ r.startLaunchTickingLocked();
+ }
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order. Note that
@@ -1195,34 +1196,37 @@
r.forceNewConfig = false;
mService.showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
- String profileFile = null;
- ParcelFileDescriptor profileFd = null;
+ ProfilerInfo profilerInfo = null;
if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
if (mService.mProfileProc == null || mService.mProfileProc == app) {
mService.mProfileProc = app;
- profileFile = mService.mProfileFile;
- profileFd = mService.mProfileFd;
- }
- }
- app.hasShownUi = true;
- app.pendingUiClean = true;
- if (profileFd != null) {
- try {
- profileFd = profileFd.dup();
- } catch (IOException e) {
- if (profileFd != null) {
- try {
- profileFd.close();
- } catch (IOException o) {
+ final String profileFile = mService.mProfileFile;
+ if (profileFile != null) {
+ ParcelFileDescriptor profileFd = mService.mProfileFd;
+ if (profileFd != null) {
+ try {
+ profileFd = profileFd.dup();
+ } catch (IOException e) {
+ if (profileFd != null) {
+ try {
+ profileFd.close();
+ } catch (IOException o) {
+ }
+ profileFd = null;
+ }
+ }
}
- profileFd = null;
+
+ profilerInfo = new ProfilerInfo(profileFile, profileFd,
+ mService.mSamplingInterval, mService.mAutoStopProfiler);
}
}
}
- ProfilerInfo profilerInfo = profileFile != null
- ? new ProfilerInfo(profileFile, profileFd, mService.mSamplingInterval,
- mService.mAutoStopProfiler) : null;
+ if (andResume) {
+ app.hasShownUi = true;
+ app.pendingUiClean = true;
+ }
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 197b51d..c8db3be 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,20 +16,26 @@
package com.android.server.am;
+import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiActivityEnergyInfo;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -38,10 +44,12 @@
import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import java.io.File;
@@ -59,15 +67,52 @@
static final String TAG = "BatteryStatsService";
static IBatteryStats sService;
-
final BatteryStatsImpl mStats;
+ final BatteryStatsHandler mHandler;
Context mContext;
private boolean mBluetoothPendingStats;
private BluetoothHeadset mBluetoothHeadset;
PowerManagerInternal mPowerManagerInternal;
+ class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
+ public static final int MSG_SYNC_EXTERNAL_STATS = 1;
+ public static final int MSG_WRITE_TO_DISK = 2;
+
+ public BatteryStatsHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SYNC_EXTERNAL_STATS:
+ updateExternalStats();
+ break;
+
+ case MSG_WRITE_TO_DISK:
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeAsyncLocked();
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void scheduleSync() {
+ if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) {
+ sendEmptyMessage(MSG_SYNC_EXTERNAL_STATS);
+ }
+ }
+ }
+
BatteryStatsService(File systemDir, Handler handler) {
- mStats = new BatteryStatsImpl(systemDir, handler);
+ // Our handler here will be accessing the disk, use a different thread than
+ // what the ActivityManagerService gave us (no I/O on that one!).
+ mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper());
+
+ // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
+ mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
}
public void publish(Context context) {
@@ -92,6 +137,8 @@
public void shutdown() {
Slog.w("BatteryStats", "Writing battery stats before shutdown...");
+
+ updateExternalStats();
synchronized (mStats) {
mStats.shutdownLocked();
}
@@ -122,6 +169,14 @@
return mStats;
}
+ /**
+ * Schedules a write to disk to occur. This will cause the BatteryStatsImpl
+ * object to update with the latest info, then write to disk.
+ */
+ public void scheduleWriteToDisk() {
+ mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK);
+ }
+
// These are for direct use by the activity manager...
void addIsolatedUid(int isolatedUid, int appUid) {
@@ -174,7 +229,10 @@
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- mStats.writeToParcel(out, 0);
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeToParcel(out, 0);
+ }
byte[] data = out.marshall();
out.recycle();
return data;
@@ -186,7 +244,10 @@
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- mStats.writeToParcel(out, 0);
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeToParcel(out, 0);
+ }
byte[] data = out.marshall();
out.recycle();
try {
@@ -663,6 +724,7 @@
}
}
+ @Override
public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
enforceCallingPermission();
synchronized (mStats) {
@@ -671,10 +733,10 @@
}
@Override
- public void noteNetworkInterfaceType(String iface, int type) {
+ public void noteNetworkInterfaceType(String iface, int networkType) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteNetworkInterfaceTypeLocked(iface, type);
+ mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
}
}
@@ -715,7 +777,22 @@
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
enforceCallingPermission();
- mStats.setBatteryState(status, health, plugType, level, temp, volt);
+ synchronized (mStats) {
+ final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ if (mStats.isOnBattery() == onBattery) {
+ // The battery state has not changed, so we don't need to sync external
+ // stats immediately.
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ return;
+ }
+ }
+
+ // Sync external stats first as the battery has changed states. If we don't sync
+ // immediately here, we may not collect the relevant data later.
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ }
}
public long getAwakeTimeBattery() {
@@ -772,12 +849,11 @@
private void dumpHelp(PrintWriter pw) {
pw.println("Battery stats (batterystats) dump options:");
- pw.println(" [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
+ pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]");
pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
pw.println(" --checkin: format output for a checkin report.");
pw.println(" --history: show only history data.");
pw.println(" --history-start <num>: show only history data starting at given time offset.");
- pw.println(" --unplugged: only output data since last unplugged.");
pw.println(" --charged: only output data since last charged.");
pw.println(" --daily: only output full daily data.");
pw.println(" --reset: reset the stats, clearing all current data.");
@@ -818,6 +894,7 @@
return i;
}
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -856,8 +933,6 @@
} else if ("-c".equals(arg)) {
useCheckinFormat = true;
flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
- } else if ("--unplugged".equals(arg)) {
- flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
} else if ("--charged".equals(arg)) {
flags |= BatteryStats.DUMP_CHARGED_ONLY;
} else if ("--daily".equals(arg)) {
@@ -868,7 +943,9 @@
pw.println("Battery stats reset.");
noOutput = true;
}
+ updateExternalStats();
} else if ("--write".equals(arg)) {
+ updateExternalStats();
synchronized (mStats) {
mStats.writeSyncLocked();
pw.println("Battery stats written.");
@@ -931,13 +1008,16 @@
if (reqUid >= 0) {
// By default, if the caller is only interested in a specific package, then
// we only dump the aggregated data since charged.
- if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_UNPLUGGED_ONLY
- |BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
+ if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
flags |= BatteryStats.DUMP_CHARGED_ONLY;
// Also if they are doing -c, we don't want history.
flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
}
}
+
+ // Fetch data from external sources and update the BatteryStatsImpl object with them.
+ updateExternalStats();
+
if (useCheckinFormat) {
List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
if (isRealCheckin) {
@@ -952,7 +1032,7 @@
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler);
+ null, mStats.mHandler, null);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
@@ -982,4 +1062,85 @@
}
}
}
+
+ // Objects for extracting data from external sources.
+ private final Object mExternalStatsLock = new Object();
+
+ @GuardedBy("mExternalStatsLock")
+ private IWifiManager mWifiManager;
+
+ // WiFi keeps an accumulated total of stats, unlike Bluetooth.
+ // Keep the last WiFi stats so we can compute a delta.
+ @GuardedBy("mExternalStatsLock")
+ private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+
+ @GuardedBy("mExternalStatsLock")
+ private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
+ if (mWifiManager == null) {
+ mWifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ if (mWifiManager == null) {
+ return null;
+ }
+ }
+
+ try {
+ // We read the data even if we are not on battery. This is so that we keep the
+ // correct delta from when we should start reading (aka when we are on battery).
+ WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo();
+ if (info != null && info.isValid()) {
+ // We will modify the last info object to be the delta, and store the new
+ // WifiActivityEnergyInfo object as our last one.
+ final WifiActivityEnergyInfo result = mLastInfo;
+ result.mTimestamp = info.getTimeStamp();
+ result.mStackState = info.getStackState();
+ result.mControllerTxTimeMs =
+ info.getControllerTxTimeMillis()- mLastInfo.mControllerTxTimeMs;
+ result.mControllerRxTimeMs =
+ info.getControllerRxTimeMillis() - mLastInfo.mControllerRxTimeMs;
+ result.mControllerIdleTimeMs =
+ info.getControllerIdleTimeMillis() - mLastInfo.mControllerIdleTimeMs;
+ result.mControllerEnergyUsed =
+ info.getControllerEnergyUsed() - mLastInfo.mControllerEnergyUsed;
+ mLastInfo = info;
+ return result;
+ }
+ } catch (RemoteException e) {
+ // Nothing to report, WiFi is dead.
+ }
+ return null;
+ }
+
+ @GuardedBy("mExternalStatsLock")
+ private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
+ BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
+ if (info != null && info.isValid()) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
+ * batterystats with that information.
+ *
+ * We first grab a lock specific to this method, then once all the data has been collected,
+ * we grab the mStats lock and update the data.
+ */
+ void updateExternalStats() {
+ synchronized (mExternalStatsLock) {
+ final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked();
+ final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
+ synchronized (mStats) {
+ mStats.updateKernelWakelocksLocked();
+ mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
+ mStats.updateWifiStateLocked(wifiEnergyInfo);
+ mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 65b2ae2..9d311f9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -234,9 +234,6 @@
private final Object mSoundEffectsLock = new Object();
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
- // Maximum volume adjust steps allowed in a single batch call.
- private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
-
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
@@ -988,6 +985,7 @@
} else {
streamType = getActiveStreamType(suggestedStreamType);
}
+ ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
// Play sounds on STREAM_RING only.
@@ -1421,6 +1419,8 @@
private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
streamType = AudioSystem.STREAM_NOTIFICATION;
+ } else {
+ streamType = mStreamVolumeAlias[streamType];
}
if (streamType == AudioSystem.STREAM_MUSIC) {
@@ -3131,12 +3131,6 @@
}
}
- private void ensureValidSteps(int steps) {
- if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
- throw new IllegalArgumentException("Bad volume adjust steps " + steps);
- }
- }
-
private void ensureValidStreamType(int streamType) {
if (streamType < 0 || streamType >= mStreamStates.length) {
throw new IllegalArgumentException("Bad stream type " + streamType);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7f47678..0b430ea 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1021,6 +1021,14 @@
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Check if the caller is authorized.
enforceControlPermission();
+ return getLegacyVpnInfoPrivileged();
+ }
+
+ /**
+ * Return the information of the current ongoing legacy VPN.
+ * Callers are responsible for checking permissions if needed.
+ */
+ public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
if (mLegacyVpnRunner == null) return null;
final LegacyVpnInfo info = new LegacyVpnInfo();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b398f41..ab56b34 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,6 +16,7 @@
package com.android.server.fingerprint;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -29,12 +30,16 @@
import com.android.server.SystemService;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.Fingerprint;
import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.IFingerprintServiceReceiver;
+
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.USE_FINGERPRINT;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -50,11 +55,14 @@
private static final int MSG_NOTIFY = 10;
+ private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NOTIFY:
- handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ FpHalMsg m = (FpHalMsg) msg.obj;
+ handleNotify(m.type, m.arg1, m.arg2, m.arg3);
break;
default:
@@ -66,7 +74,7 @@
private int mHalDeviceId;
private static final int STATE_IDLE = 0;
- private static final int STATE_LISTENING = 1;
+ private static final int STATE_AUTHENTICATING = 1;
private static final int STATE_ENROLLING = 2;
private static final int STATE_REMOVING = 3;
private static final long MS_PER_SEC = 1000;
@@ -76,7 +84,10 @@
int state;
int userId;
public TokenWatcher tokenWatcher;
- IBinder getToken() { return tokenWatcher.getToken(); }
+
+ IBinder getToken() {
+ return tokenWatcher.getToken();
+ }
}
private class TokenWatcher implements IBinder.DeathRecipient {
@@ -86,7 +97,10 @@
this.token = new WeakReference<IBinder>(token);
}
- IBinder getToken() { return token.get(); }
+ IBinder getToken() {
+ return token.get();
+ }
+
public void binderDied() {
mClients.remove(token);
this.token = null;
@@ -112,21 +126,42 @@
// TODO: Move these into separate process
// JNI methods to communicate from FingerprintManagerService to HAL
- static native int nativeEnroll(int timeout);
+ static native int nativeEnroll(int timeout, int groupId);
+
+ static native int nativeAuthenticate(long sessionId, int groupId);
+
static native int nativeEnrollCancel();
- static native int nativeRemove(int fingerprintId);
+
+ static native int nativeRemove(int fingerId, int groupId);
+
static native int nativeOpenHal();
+
static native int nativeCloseHal();
+
static native void nativeInit(MessageQueue queue, FingerprintService service);
- // JNI methods for communicating from HAL to clients
- void notify(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ static final class FpHalMsg {
+ int type; // Type of the message. One of the constants in fingerprint.h
+ int arg1; // optional arguments
+ int arg2;
+ int arg3;
+
+ FpHalMsg(int type, int arg1, int arg2, int arg3) {
+ this.type = type;
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
}
- void handleNotify(int msg, int arg1, int arg2) {
- Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
- + ", " + mClients.size() + " clients");
+ // JNI methods for communicating from HAL to clients
+ void notify(int type, int arg1, int arg2, int arg3) {
+ mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget();
+ }
+
+ void handleNotify(int type, int arg1, int arg2, int arg3) {
+ Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", "
+ + mClients.size() + " clients");
for (int i = 0; i < mClients.size(); i++) {
if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i));
ClientData clientData = mClients.valueAt(i);
@@ -134,21 +169,20 @@
if (DEBUG) Slog.v(TAG, "clientData is invalid!!");
continue;
}
- switch (msg) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ switch (type) {
case FingerprintManager.FINGERPRINT_ERROR: {
- final int error = arg1;
try {
- clientData.receiver.onError(error);
+ clientData.receiver.onError(mHalDeviceId, arg1 /* error */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- break;
+ break;
case FingerprintManager.FINGERPRINT_ACQUIRED: {
- final int acquireInfo = arg1;
try {
- clientData.receiver.onAcquired(acquireInfo);
+ clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -156,9 +190,9 @@
break;
}
case FingerprintManager.FINGERPRINT_PROCESSED: {
- final int fingerId = arg1;
try {
- clientData.receiver.onProcessed(fingerId);
+ clientData.receiver
+ .onProcessed(mHalDeviceId, arg1 /* fingerId */, arg2 /* groupId */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -167,11 +201,13 @@
}
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
final int fingerId = arg1;
- final int remaining = arg2;
+ final int groupId = arg2;
+ final int remaining = arg3;
if (clientData.state == STATE_ENROLLING) {
// Only send enroll updates to clients that are actually enrolling
try {
- clientData.receiver.onEnrollResult(fingerId, remaining);
+ clientData.receiver.onEnrollResult(mHalDeviceId, fingerId, groupId,
+ remaining);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -179,8 +215,8 @@
// Update the database with new finger id.
// TODO: move to client code (Settings)
if (remaining == 0) {
- FingerprintUtils.addFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId,
+ clientData.userId);
clientData.state = STATE_IDLE; // Nothing left to do
}
} else {
@@ -191,30 +227,50 @@
}
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
int fingerId = arg1;
- if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
- FingerprintUtils.removeFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ int groupId = arg2;
+ if (fingerId == 0) {
+ throw new IllegalStateException("Got illegal id from HAL");
+ }
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver,
+ clientData.userId);
if (clientData.receiver != null) {
try {
- clientData.receiver.onRemoved(fingerId);
+ clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
}
- break;
+ break;
}
}
}
- void startEnroll(IBinder token, long timeout, int userId) {
+ void startEnroll(IBinder token, int groupId, int flags) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
clientData.state = STATE_ENROLLING;
- nativeEnroll((int) (timeout / MS_PER_SEC));
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeEnroll(timeout, groupId);
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startAuthenticate(IBinder token, long sessionId, int groupId, int flags) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
+ clientData.state = STATE_AUTHENTICATING;
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeAuthenticate(sessionId, groupId);
} else {
Slog.w(TAG, "enroll(): No listener registered");
}
@@ -224,7 +280,7 @@
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
nativeEnrollCancel();
} else {
Slog.w(TAG, "enrollCancel(): No listener registered");
@@ -238,7 +294,7 @@
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_REMOVING;
// The fingerprint id will be removed when we get confirmation from the HAL
- int result = nativeRemove(fingerId);
+ int result = nativeRemove(fingerId, userId);
if (result != 0) {
Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
}
@@ -251,7 +307,7 @@
if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
if (mClients.get(token) == null) {
ClientData clientData = new ClientData();
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
clientData.receiver = receiver;
clientData.userId = userId;
clientData.tokenWatcher = new TokenWatcher(token);
@@ -266,7 +322,7 @@
}
}
- void removeListener(IBinder token, int userId) {
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
ClientData clientData = mClients.get(token);
if (clientData != null) {
@@ -278,61 +334,91 @@
mClients.remove(token);
}
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ ContentResolver resolver = mContext.getContentResolver();
+ int[] ids = FingerprintUtils.getFingerprintIdsForUser(resolver, groupId);
+ List<Fingerprint> result = new ArrayList<Fingerprint>();
+ for (int i = 0; i < ids.length; i++) {
+ // TODO: persist names in Settings
+ CharSequence name = "Finger" + ids[i];
+ final int group = 0; // TODO
+ final int fingerId = ids[i];
+ final long deviceId = 0; // TODO
+ Fingerprint item = new Fingerprint(name, 0, ids[i], 0);
+ result.add(item);
+ }
+ return result;
+ }
+
void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission, "Must have "
- + permission + " permission.");
+ getContext().enforceCallingOrSelfPermission(permission,
+ "Must have " + permission + " permission.");
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- @Override // Binder call
- public void enroll(IBinder token, long timeout, int userId) {
+ @Override
+ // Binder call
+ public void enroll(IBinder token, int groupId, int flags) {
checkPermission(MANAGE_FINGERPRINT);
- startEnroll(token, timeout, userId);
+ startEnroll(token, groupId, flags);
}
- @Override // Binder call
- public void enrollCancel(IBinder token,int userId) {
- checkPermission(MANAGE_FINGERPRINT);
- startEnrollCancel(token, userId);
- }
-
- @Override // Binder call
- public void remove(IBinder token, int fingerprintId, int userId) {
- checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
- startRemove(token, fingerprintId, userId);
- }
-
- @Override // Binder call
- public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
- {
+ @Override
+ // Binder call
+ public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
checkPermission(USE_FINGERPRINT);
- addListener(token, receiver, userId);
- }
-
- @Override // Binder call
- public void stopListening(IBinder token, int userId) {
- checkPermission(USE_FINGERPRINT);
- removeListener(token, userId);
- }
-
- @Override // Binder call
- public boolean isHardwareDetected() {
- checkPermission(USE_FINGERPRINT);
- return mHalDeviceId != 0;
+ startAuthenticate(token, sessionId, groupId, flags);
}
@Override
- public void rename(int fpId, String name) {
+ // Binder call
+ public void remove(IBinder token, int fingerId, int groupId) {
+ checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
+ startRemove(token, fingerId, groupId);
+ }
+
+ @Override
+ // Binder call
+ public void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+ checkPermission(USE_FINGERPRINT);
+ FingerprintService.this.addListener(token, receiver, userId);
+ }
+
+ @Override
+ // Binder call
+ public void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
+ checkPermission(USE_FINGERPRINT);
+ FingerprintService.this.removeListener(token, receiver);
+ }
+
+ @Override
+ // Binder call
+ public boolean isHardwareDetected(long deviceId) {
+ checkPermission(USE_FINGERPRINT);
+ return mHalDeviceId != 0; // TODO
+ }
+
+ @Override
+ // Binder call
+ public void rename(int fingerId, int groupId, String name) {
checkPermission(MANAGE_FINGERPRINT);
+ Slog.w(TAG, "rename id=" + fingerId + ",gid=" + groupId + ",name=" + name);
// TODO
}
+
+ @Override
+ // Binder call
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ checkPermission(USE_FINGERPRINT);
+ return FingerprintService.this.getEnrolledFingerprints(groupId);
+ }
}
@Override
public void onStart() {
- publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
- mHalDeviceId = nativeOpenHal();
- if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ mHalDeviceId = nativeOpenHal();
+ if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7c93e56..d5cb5e3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -251,7 +251,9 @@
}
int targetAddress = targetDevice.getLogicalAddress();
ActiveSource active = getActiveSource();
- if (active.isValid() && targetAddress == active.logicalAddress) {
+ if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON
+ && active.isValid()
+ && targetAddress == active.logicalAddress) {
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b5036db..09d0501 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -40,6 +40,7 @@
import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeadObjectException;
@@ -887,6 +888,14 @@
}
}
+ public void playFromUri(Uri uri, Bundle extras) {
+ try {
+ mCb.onPlayFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in playFromUri.", e);
+ }
+ }
+
public void skipToTrack(long id) {
try {
mCb.onSkipToTrack(id);
@@ -1103,6 +1112,11 @@
}
@Override
+ public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
+ mSessionCb.playFromUri(uri, extras);
+ }
+
+ @Override
public void skipToQueueItem(long id) {
mSessionCb.skipToTrack(id);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 20f5f97..01c6662 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -22,21 +22,28 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.TrafficStats.UID_TETHERING;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.os.Binder;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.IntArray;
import libcore.io.IoUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -129,6 +136,23 @@
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
}
+ public int[] getRelevantUids() {
+ final int callerUid = Binder.getCallingUid();
+ IntArray uids = new IntArray();
+ for (int i = 0; i < mStats.size(); i++) {
+ final Key key = mStats.keyAt(i);
+ if (isAccessibleToUser(key.uid, callerUid)) {
+ int j = uids.binarySearch(key.uid);
+
+ if (j < 0) {
+ j = ~j;
+ uids.add(j, key.uid);
+ }
+ }
+ }
+ return uids.toArray();
+ }
+
/**
* Combine all {@link NetworkStatsHistory} in this collection which match
* the requested parameters.
@@ -144,8 +168,18 @@
*/
public NetworkStatsHistory getHistory(
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
+ final int callerUid = Binder.getCallingUid();
+ if (!isAccessibleToUser(uid, callerUid)) {
+ throw new SecurityException("Network stats history of uid " + uid
+ + " is forbidden for caller " + callerUid);
+ }
+
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mBucketDuration, estimateBuckets(), fields);
+ mBucketDuration, start == end ? 1 : estimateBuckets(), fields);
+
+ // shortcut when we know stats will be empty
+ if (start == end) return combined;
+
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
final boolean setMatches = set == SET_ALL || key.set == set;
@@ -166,15 +200,16 @@
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- NetworkStatsHistory.Entry historyEntry = null;
-
// shortcut when we know stats will be empty
if (start == end) return stats;
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ NetworkStatsHistory.Entry historyEntry = null;
+
+ final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (templateMatches(template, key.ident)) {
+ if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)) {
final NetworkStatsHistory value = mStats.valueAt(i);
historyEntry = value.getValues(start, end, now, historyEntry);
@@ -534,6 +569,12 @@
}
}
+ private static boolean isAccessibleToUser(int uid, int callerUid) {
+ return callerUid == android.os.Process.SYSTEM_UID ||
+ uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ }
+
/**
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
* in the given {@link NetworkIdentitySet}.
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0b596aa..50e03a2 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -62,9 +62,13 @@
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
+import android.Manifest;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -93,7 +97,9 @@
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -116,6 +122,7 @@
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -429,7 +436,11 @@
@Override
public INetworkStatsSession openSession() {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ return openSessionForUsageStats(null);
+ }
+
+ @Override
+ public INetworkStatsSession openSessionForUsageStats(final String callingPackage) {
assertBandwidthControlEnabled();
// return an IBinder which holds strong references to any loaded stats
@@ -438,6 +449,7 @@
return new INetworkStatsSession.Stub() {
private NetworkStatsCollection mUidComplete;
private NetworkStatsCollection mUidTagComplete;
+ private String mCallingPackage = callingPackage;
private NetworkStatsCollection getUidComplete() {
synchronized (mStatsLock) {
@@ -458,8 +470,29 @@
}
@Override
+ public int[] getRelevantUids() {
+ enforcePermissionForManagedAdmin(mCallingPackage);
+ return getUidComplete().getRelevantUids();
+ }
+
+ @Override
+ public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
+ long end) {
+ enforcePermission(mCallingPackage);
+ NetworkStats result = new NetworkStats(end - start, 1);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result.combineAllValues(internalGetSummaryForNetwork(template, start, end));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return result;
+ }
+
+ @Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
+ enforcePermission(mCallingPackage);
return internalGetSummaryForNetwork(template, start, end);
}
@@ -471,6 +504,7 @@
@Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
+ enforcePermissionForManagedAdmin(mCallingPackage);
final NetworkStats stats = getUidComplete().getSummary(template, start, end);
if (includeTags) {
final NetworkStats tagStats = getUidTagComplete()
@@ -483,6 +517,7 @@
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
+ enforcePermissionForManagedAdmin(mCallingPackage);
if (tag == TAG_NONE) {
return getUidComplete().getHistory(template, uid, set, tag, fields);
} else {
@@ -498,6 +533,53 @@
};
}
+ private boolean hasAppOpsPermission(String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ boolean appOpsAllow = false;
+ if (callingPackage != null) {
+ AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
+
+ final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ // The default behavior here is to check if PackageManager has given the app
+ // permission.
+ final int permissionCheck = mContext.checkCallingPermission(
+ Manifest.permission.PACKAGE_USAGE_STATS);
+ appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED;
+ }
+ appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED);
+ }
+ return appOpsAllow;
+ }
+
+ private void enforcePermissionForManagedAdmin(String callingPackage) {
+ boolean hasPermission = hasAppOpsPermission(callingPackage);
+ if (!hasPermission) {
+ // Profile and device owners are exempt from permission checking.
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+ DevicePolicyManagerInternal.class);
+ if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
+ || dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) {
+ return;
+ }
+ }
+ if (!hasPermission) {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ }
+ }
+
+ private void enforcePermission(String callingPackage) {
+ boolean appOpsAllow = hasAppOpsPermission(callingPackage);
+ if (!appOpsAllow) {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ }
+ }
+
+
/**
* Return network summary, splicing between DEV and XT stats when
* appropriate.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ad51457..1b8ed22 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -248,8 +248,8 @@
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
- private static final boolean RUNTIME_PERMISSIONS_ENABLED =
- SystemProperties.getInt("ro.runtime.premissions.enabled", 0) == 1;
+ static final boolean RUNTIME_PERMISSIONS_ENABLED =
+ SystemProperties.getInt("ro.runtime.permissions.enabled", 0) == 1;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
@@ -275,6 +275,7 @@
static final int SCAN_TRUSTED_OVERLAY = 1<<9;
static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
static final int SCAN_REPLACING = 1<<11;
+ static final int SCAN_REQUIRE_KNOWN = 1<<12;
static final int REMOVE_CHATTY = 1<<16;
@@ -339,7 +340,7 @@
/** Permission grant: grant the permission as an install permission. */
private static final int GRANT_INSTALL = 2;
- /** Permission grant: grant the permission as a runtime permission. */
+ /** Permission grant: grant the permission as a runtime one. */
private static final int GRANT_RUNTIME = 3;
/** Permission grant: grant as runtime a permission that was granted as an install time one. */
@@ -1699,10 +1700,10 @@
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirLI(mAppInstallDir, 0, scanFlags, 0);
+ scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
- scanFlags, 0);
+ scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
* Remove disable package settings for any updated system
@@ -1810,7 +1811,26 @@
+ mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
-
+
+
+ // We keep track for which users we granted permissions to be able
+ // to grant runtime permissions to system apps for newly appeared
+ // users. If we supported runtime permissions during the previous
+ // boot, then we already granted permissions for all device users.
+ // In such a case we set the users for which we granted permissions
+ // to avoid clobbering of runtime permissions we granted to system
+ // apps but the user revoked later.
+ if (PackageManagerService.RUNTIME_PERMISSIONS_ENABLED &&
+ mSettings.mRuntimePermissionEnabled) {
+ final int[] userIds = UserManagerService.getInstance().getUserIds();
+ for (PackageSetting ps : mSettings.mPackages.values()) {
+ ps.setPermissionsUpdatedForUserIds(userIds);
+ }
+ for (SharedUserSetting sus : mSettings.mSharedUsers.values()) {
+ sus.setPermissionsUpdatedForUserIds(userIds);
+ }
+ }
+
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
@@ -1842,7 +1862,6 @@
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
-
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
@@ -5259,6 +5278,28 @@
+ " already installed. Skipping duplicate.");
}
+ // If we're only installing presumed-existing packages, require that the
+ // scanned APK is both already known and at the path previously established
+ // for it. Previously unknown packages we pick up normally, but if we have an
+ // a priori expectation about this package's install presence, enforce it.
+ if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
+ PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
+ if (known != null) {
+ if (DEBUG_PACKAGE_SCANNING) {
+ Log.d(TAG, "Examining " + pkg.codePath
+ + " and requiring known paths " + known.codePathString
+ + " & " + known.resourcePathString);
+ }
+ if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
+ || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
+ throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
+ "Application package " + pkg.packageName
+ + " found at " + pkg.applicationInfo.getCodePath()
+ + " but expected at " + known.codePathString + "; ignoring.");
+ }
+ }
+ }
+
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
@@ -6967,10 +7008,15 @@
PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
- boolean changedPermission = false;
+ final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+
+ int[] upgradeUserIds = PermissionsState.USERS_NONE;
+ int[] changedRuntimePermissionUserIds = PermissionsState.USERS_NONE;
+
+ boolean changedInstallPermission = false;
if (replace) {
- ps.permissionsFixed = false;
+ ps.installPermissionsFixed = false;
origPermissions = new PermissionsState(permissionsState);
permissionsState.reset();
}
@@ -7022,16 +7068,32 @@
// For legacy apps dangerous permissions are install time ones.
grant = GRANT_INSTALL;
} else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- // For modern system apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL;
- } else {
+ final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds();
if (origPermissions.hasInstallPermission(bp.name)) {
- // For legacy apps that became modern, install becomes runtime.
+ // If a system app had an install permission, then the app was
+ // upgraded and we grant the permissions as runtime to all users.
grant = GRANT_UPGRADE;
- } else if (replace) {
- // For upgraded modern apps keep runtime permissions unchanged.
+ upgradeUserIds = currentUserIds;
+ } else if (!Arrays.equals(updatedUserIds, currentUserIds)) {
+ // If users changed since the last permissions update for a
+ // system app, we grant the permission as runtime to the new users.
+ grant = GRANT_UPGRADE;
+ upgradeUserIds = currentUserIds;
+ for (int userId : updatedUserIds) {
+ upgradeUserIds = ArrayUtils.removeInt(upgradeUserIds, userId);
+ }
+ } else {
+ // Otherwise, we grant the permission as runtime if the app
+ // already had it, i.e. we preserve runtime permissions.
grant = GRANT_RUNTIME;
}
+ } else if (origPermissions.hasInstallPermission(bp.name)) {
+ // For legacy apps that became modern, install becomes runtime.
+ grant = GRANT_UPGRADE;
+ upgradeUserIds = currentUserIds;
+ } else if (replace) {
+ // For upgraded modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
}
} break;
@@ -7049,7 +7111,7 @@
}
if (grant != GRANT_DENIED) {
- if (!isSystemApp(ps) && ps.permissionsFixed) {
+ if (!isSystemApp(ps) && ps.installPermissionsFixed) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it.
if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
@@ -7067,7 +7129,7 @@
// Grant an install permission.
if (permissionsState.grantInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedPermission = true;
+ changedInstallPermission = true;
}
} break;
@@ -7075,9 +7137,11 @@
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.hasRuntimePermission(bp.name, userId)) {
- if (permissionsState.grantRuntimePermission(bp, userId) !=
+ if (permissionsState.grantRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedPermission = true;
+ // If we cannot put the permission as it was, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
}
}
}
@@ -7086,10 +7150,12 @@
case GRANT_UPGRADE: {
// Grant runtime permissions for a previously held install permission.
permissionsState.revokeInstallPermission(bp);
- for (int userId : UserManagerService.getInstance().getUserIds()) {
+ for (int userId : upgradeUserIds) {
if (permissionsState.grantRuntimePermission(bp, userId) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedPermission = true;
+ // If we granted the permission, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
}
}
} break;
@@ -7106,7 +7172,7 @@
} else {
if (permissionsState.revokeInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedPermission = true;
+ changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
@@ -7126,12 +7192,19 @@
}
}
- if ((changedPermission || replace) && !ps.permissionsFixed &&
+ if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
- ps.permissionsFixed = true;
+ ps.installPermissionsFixed = true;
+ }
+
+ ps.setPermissionsUpdatedForUserIds(changedRuntimePermissionUserIds);
+
+ // Persist the runtime permissions state for users with changes.
+ for (int userId : changedRuntimePermissionUserIds) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, true);
}
}
@@ -13358,6 +13431,11 @@
}
}
+ void newUserCreatedLILPw(int userHandle) {
+ // Adding a user requires updating runtime permissions for system apps.
+ updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
+ }
+
@Override
public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 9e8b3df..35df33b 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -92,7 +92,7 @@
PackageSignatures signatures = new PackageSignatures();
- boolean permissionsFixed;
+ boolean installPermissionsFixed;
PackageKeySetData keySetData = new PackageKeySetData();
@@ -145,7 +145,7 @@
signatures = new PackageSignatures(base.signatures);
- permissionsFixed = base.permissionsFixed;
+ installPermissionsFixed = base.installPermissionsFixed;
userState.clear();
for (int i=0; i<base.userState.size(); i++) {
userState.put(base.userState.keyAt(i),
@@ -198,6 +198,7 @@
* Make a shallow copy of this package settings.
*/
public void copyFrom(PackageSettingBase base) {
+ setPermissionsUpdatedForUserIds(base.getPermissionsUpdatedForUserIds());
getPermissionsState().copyFrom(base.getPermissionsState());
primaryCpuAbiString = base.primaryCpuAbiString;
secondaryCpuAbiString = base.secondaryCpuAbiString;
@@ -206,7 +207,7 @@
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
signatures = base.signatures;
- permissionsFixed = base.permissionsFixed;
+ installPermissionsFixed = base.installPermissionsFixed;
userState.clear();
for (int i=0; i<base.userState.size(); i++) {
userState.put(base.userState.keyAt(i), base.userState.valueAt(i));
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 3e0e342..705abf8 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -55,9 +55,9 @@
/** The permission operation failed. */
public static final int PERMISSION_OPERATION_FAILURE = 3;
- private static final int[] USERS_ALL = {UserHandle.USER_ALL};
+ public static final int[] USERS_ALL = {UserHandle.USER_ALL};
- private static final int[] USERS_NONE = {};
+ public static final int[] USERS_NONE = {};
private static final int[] NO_GIDS = {};
@@ -149,6 +149,9 @@
* #PERMISSION_OPERATION_FAILURE}.
*/
public int grantRuntimePermission(BasePermission permission, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
return grantPermission(permission, userId);
}
@@ -162,6 +165,9 @@
* #PERMISSION_OPERATION_FAILURE}.
*/
public int revokeRuntimePermission(BasePermission permission, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
return revokePermission(permission, userId);
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index d350c09..3a7b6ee 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -17,13 +17,15 @@
package com.android.server.pm;
import android.content.pm.ApplicationInfo;
-import android.util.ArraySet;
+
+import java.util.Arrays;
abstract class SettingBase {
int pkgFlags;
int pkgPrivateFlags;
private final PermissionsState mPermissionsState;
+ private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE;
SettingBase(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
@@ -35,12 +37,29 @@
pkgFlags = base.pkgFlags;
pkgPrivateFlags = base.pkgPrivateFlags;
mPermissionsState = new PermissionsState(base.mPermissionsState);
+ setPermissionsUpdatedForUserIds(base.mPermissionsUpdatedForUserIds);
}
public PermissionsState getPermissionsState() {
return mPermissionsState;
}
+ public int[] getPermissionsUpdatedForUserIds() {
+ return mPermissionsUpdatedForUserIds;
+ }
+
+ public void setPermissionsUpdatedForUserIds(int[] userIds) {
+ if (Arrays.equals(mPermissionsUpdatedForUserIds, userIds)) {
+ return;
+ }
+
+ if (userIds == PermissionsState.USERS_NONE || userIds == PermissionsState.USERS_ALL) {
+ mPermissionsUpdatedForUserIds = userIds;
+ } else {
+ mPermissionsUpdatedForUserIds = Arrays.copyOf(userIds, userIds.length);
+ }
+ }
+
void setFlags(int pkgFlags) {
this.pkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 82aa74a..0a2389f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -175,6 +175,7 @@
private static final String ATTR_HIDDEN = "hidden";
private static final String ATTR_INSTALLED = "inst";
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
+ private static final String ATTR_RUNTIME_PERMSISSIONS_ENABLED = "runtime-permissions-enabled";
private final Object mLock;
private final Context mContext;
@@ -201,6 +202,10 @@
int mInternalSdkPlatform;
int mExternalSdkPlatform;
+
+ // Whether runtime permissions are enabled.
+ boolean mRuntimePermissionEnabled;
+
/**
* The current database version for apps on internal storage. This is
* used to upgrade the format of the packages.xml database not necessarily
@@ -1645,6 +1650,8 @@
serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.attribute(null, "fingerprint", mFingerprint);
+ serializer.attribute(null, ATTR_RUNTIME_PERMSISSIONS_ENABLED,
+ String.valueOf(PackageManagerService.RUNTIME_PERMISSIONS_ENABLED));
serializer.endTag(null, "last-platform-version");
serializer.startTag(null, "database-version");
@@ -2141,6 +2148,8 @@
} catch (NumberFormatException e) {
}
mFingerprint = parser.getAttributeValue(null, "fingerprint");
+ mRuntimePermissionEnabled = XmlUtils.readBooleanAttribute(parser,
+ ATTR_RUNTIME_PERMSISSIONS_ENABLED);
} else if (tagName.equals("database-version")) {
mInternalDatabaseVersion = mExternalDatabaseVersion = 0;
try {
@@ -2990,7 +2999,7 @@
} else if (tagName.equals(TAG_PERMISSIONS)) {
readInstallPermissionsLPr(parser,
packageSetting.getPermissionsState());
- packageSetting.permissionsFixed = true;
+ packageSetting.installPermissionsFixed = true;
} else if (tagName.equals("proper-signing-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
packageSetting.keySetData.setProperSigningKeySet(id);
@@ -3010,8 +3019,6 @@
XmlUtils.skipCurrentTag(parser);
}
}
-
-
} else {
XmlUtils.skipCurrentTag(parser);
}
@@ -3565,7 +3572,8 @@
pw.println(ps.installerPackageName);
}
pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(prefix); pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
+ pw.print(prefix); pw.print(" installPermissionsFixed=");
+ pw.print(ps.installPermissionsFixed);
pw.print(" installStatus="); pw.println(ps.installStatus);
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 26ecb72..8cc9d19 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1219,6 +1219,7 @@
updateUserIdsLocked();
Bundle restrictions = new Bundle();
mUserRestrictions.append(userId, restrictions);
+ mPm.newUserCreatedLILPw(userId);
}
}
if (userInfo != null) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 1349926..c48367e 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -78,6 +78,7 @@
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
+ private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
private final Object mLock = new Object();
@@ -92,6 +93,7 @@
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
private final Intent mScreenOffIntent;
+ private final Intent mScreenBrightnessBoostIntent;
// The current interactive state.
private int mActualInteractiveState;
@@ -128,6 +130,10 @@
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+ mScreenBrightnessBoostIntent =
+ new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED);
+ mScreenBrightnessBoostIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
// Initialize interactive state for battery stats.
try {
@@ -349,6 +355,19 @@
}
/**
+ * Called when screen brightness boost begins or ends.
+ */
+ public void onScreenBrightnessBoostChanged() {
+ if (DEBUG) {
+ Slog.d(TAG, "onScreenBrightnessBoostChanged");
+ }
+
+ mSuspendBlocker.acquire();
+ Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+ /**
* Called when there has been user activity.
*/
public void onUserActivity(int event, int uid) {
@@ -457,6 +476,22 @@
}
}
+ private void sendBrightnessBoostChangedBroadcast() {
+ if (DEBUG) {
+ Slog.d(TAG, "Sending brightness boost changed broadcast.");
+ }
+
+ mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null,
+ mScreeBrightnessBoostChangedDone, mHandler, 0, null, null);
+ }
+
+ private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mSuspendBlocker.release();
+ }
+ };
+
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
@@ -539,6 +574,9 @@
case MSG_WIRELESS_CHARGING_STARTED:
playWirelessChargingStartedSound();
break;
+ case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
+ sendBrightnessBoostChangedBroadcast();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 33b451d..6c8959c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1903,6 +1903,7 @@
}
}
mScreenBrightnessBoostInProgress = false;
+ mNotifier.onScreenBrightnessBoostChanged();
userActivityNoUpdateLocked(now,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
}
@@ -2284,7 +2285,10 @@
Slog.i(TAG, "Brightness boost activated (uid " + uid +")...");
mLastScreenBrightnessBoostTime = eventTime;
- mScreenBrightnessBoostInProgress = true;
+ if (!mScreenBrightnessBoostInProgress) {
+ mScreenBrightnessBoostInProgress = true;
+ mNotifier.onScreenBrightnessBoostChanged();
+ }
mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
userActivityNoUpdateLocked(eventTime,
@@ -2293,6 +2297,12 @@
}
}
+ private boolean isScreenBrightnessBoostedInternal() {
+ synchronized (mLock) {
+ return mScreenBrightnessBoostInProgress;
+ }
+ }
+
/**
* Called when a screen brightness boost timeout has occurred.
*
@@ -3237,6 +3247,16 @@
}
@Override // Binder call
+ public boolean isScreenBrightnessBoosted() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isScreenBrightnessBoostedInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 09bc2ab..957eb9e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3056,7 +3056,7 @@
}
}
- if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ if (true || DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
win.mEnforceSizeCompat =
@@ -4171,8 +4171,8 @@
}
synchronized(mWindowMap) {
- if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition,
- new RuntimeException("here").fillInStackTrace());
+ if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition
+ + " Callers=" + Debug.getCallers(5));
if (mAppTransition.isTransitionSet()) {
mAppTransition.setReady();
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
index 94853b8..cb70144 100644
--- a/services/core/jni/com_android_server_UsbMidiDevice.cpp
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -94,9 +94,20 @@
return fds;
}
+static void
+android_server_UsbMidiDevice_close(JNIEnv *env, jobject /* thiz */, jobjectArray fds)
+{
+ int count = env->GetArrayLength(fds);
+ for (int i = 0; i < count; i++) {
+ jobject fd = env->GetObjectArrayElement(fds, i);
+ close(jniGetFDFromFileDescriptor(env, fd));
+ }
+}
+
static JNINativeMethod method_table[] = {
{ "nativeGetSubdeviceCount", "(II)I", (void*)android_server_UsbMidiDevice_get_subdevice_count },
{ "nativeOpen", "(III)[Ljava/io/FileDescriptor;", (void*)android_server_UsbMidiDevice_open },
+ { "nativeClose", "([Ljava/io/FileDescriptor;)V", (void*)android_server_UsbMidiDevice_close },
};
int register_android_server_UsbMidiDevice(JNIEnv *env)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d02b2d6..73b5de1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3174,7 +3174,9 @@
}
PersistentDataBlockManager manager = (PersistentDataBlockManager)
mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
- manager.wipe();
+ if (manager != null) {
+ manager.wipe();
+ }
}
boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 23e1970..c041029 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -459,7 +459,7 @@
}
/* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
- if (enabled) {
+ if (enabled && mPeripheralMidiDevice == null) {
Bundle properties = new Bundle();
Resources r = mContext.getResources();
properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
@@ -469,7 +469,7 @@
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
- } else if (mPeripheralMidiDevice != null) {
+ } else if (!enabled && mPeripheralMidiDevice != null) {
IoUtils.closeQuietly(mPeripheralMidiDevice);
mPeripheralMidiDevice = null;
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 41cf2ef..6adb8be 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -126,6 +126,8 @@
private boolean mAdbEnabled;
private boolean mAudioSourceEnabled;
private boolean mMidiEnabled;
+ private int mMidiCard;
+ private int mMidiDevice;
private Map<String, List<Pair<String, String>>> mOemModeMap;
private String[] mAccessoryStrings;
private UsbDebuggingManager mDebuggingManager;
@@ -363,18 +365,6 @@
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
- // Upgrade step for previous versions that used persist.service.adb.enable
- String value = SystemProperties.get("persist.service.adb.enable", "");
- if (value.length() > 0) {
- char enable = value.charAt(0);
- if (enable == '1') {
- setAdbEnabled(true);
- } else if (enable == '0') {
- setAdbEnabled(false);
- }
- SystemProperties.set("persist.service.adb.enable", "");
- }
-
// register observer to listen for settings changes
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
@@ -623,26 +613,24 @@
private void updateMidiFunction() {
boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
if (enabled != mMidiEnabled) {
- int card = -1;
- int device = -1;
-
if (enabled) {
Scanner scanner = null;
try {
scanner = new Scanner(new File(MIDI_ALSA_PATH));
- card = scanner.nextInt();
- device = scanner.nextInt();
+ mMidiCard = scanner.nextInt();
+ mMidiDevice = scanner.nextInt();
} catch (FileNotFoundException e) {
Slog.e(TAG, "could not open MIDI PCM file", e);
+ enabled = false;
} finally {
if (scanner != null) {
scanner.close();
}
}
}
- mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
mMidiEnabled = enabled;
}
+ mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index f23bb93..3b65709 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -47,6 +47,8 @@
private static final int BUFFER_SIZE = 512;
+ private final FileDescriptor[] mFileDescriptors;
+
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
// streams for reading from ALSA driver
@@ -69,7 +71,7 @@
return null;
}
- UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+ UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors);
if (!midiDevice.register(context, properties)) {
IoUtils.closeQuietly(midiDevice);
Log.e(TAG, "createDeviceServer failed");
@@ -78,14 +80,15 @@
return midiDevice;
}
- private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
- int inputCount = inputFiles.length;
- int outputCount = outputFiles.length;
+ private UsbMidiDevice(FileDescriptor[] fileDescriptors) {
+ mFileDescriptors = fileDescriptors;
+ int inputCount = fileDescriptors.length;
+ int outputCount = fileDescriptors.length;
mPollFDs = new StructPollfd[inputCount];
mInputStreams = new FileInputStream[inputCount];
for (int i = 0; i < inputCount; i++) {
- FileDescriptor fd = inputFiles[i];
+ FileDescriptor fd = fileDescriptors[i];
StructPollfd pollfd = new StructPollfd();
pollfd.fd = fd;
pollfd.events = (short)OsConstants.POLLIN;
@@ -95,7 +98,7 @@
mOutputStreams = new FileOutputStream[outputCount];
for (int i = 0; i < outputCount; i++) {
- mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
+ mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
}
mInputPortReceivers = new MidiReceiver[inputCount];
@@ -176,8 +179,10 @@
for (int i = 0; i < mOutputStreams.length; i++) {
mOutputStreams[i].close();
}
+ nativeClose(mFileDescriptors);
}
private static native int nativeGetSubdeviceCount(int card, int device);
private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
+ private static native void nativeClose(FileDescriptor[] fileDescriptors);
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 22b7bb1..6fa653d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -223,7 +223,7 @@
//**********************************************************************************************
// Next CAPABILITY value: 0x00080000
- //**********************************************************************************************
+ //******************************************************************************************
private final Uri mHandle;
private final int mHandlePresentation;
@@ -323,7 +323,7 @@
builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
}
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index a335e47..082474b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -171,7 +171,7 @@
* Connection is using WIFI.
* @hide
*/
- public static final int CAPABILITY_WIFI = 0x000010000;
+ public static final int CAPABILITY_WIFI = 0x00010000;
/**
* Indicates that the current device callback number should be shown.
@@ -292,7 +292,7 @@
builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
}
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b44fa6c..386b6aa 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4057,6 +4057,34 @@
}
/**
+ * Returns the Status of Volte
+ *@hide
+ */
+ public boolean isVolteEnabled() {
+ try {
+ return getITelephony().isVolteEnabled();
+ } catch (RemoteException ex) {
+ return false;
+ } catch (NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the Status of Wi-Fi Calling
+ *@hide
+ */
+ public boolean isWifiCallingEnabled() {
+ try {
+ return getITelephony().isWifiCallingEnabled();
+ } catch (RemoteException ex) {
+ return false;
+ } catch (NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
* Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
*
* @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f9e15f3..c18e3b6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -901,6 +901,18 @@
boolean isImsRegistered();
/**
+ * Returns the Status of Wi-Fi Calling
+ *@hide
+ */
+ boolean isWifiCallingEnabled();
+
+ /**
+ * Returns the Status of Volte
+ *@hide
+ */
+ boolean isVolteEnabled();
+
+ /**
* Returns the unique device ID of phone, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
diff --git a/tools/layoutlib/.idea/libraries/guava.xml b/tools/layoutlib/.idea/libraries/guava.xml
index d47fc06..eb60719 100644
--- a/tools/layoutlib/.idea/libraries/guava.xml
+++ b/tools/layoutlib/.idea/libraries/guava.xml
@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="guava">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar!/" />
+ <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="file://$PROJECT_DIR$/../../../../external/guava/guava/src" />
+ <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
index d97d82c..0b22717 100644
--- a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
+++ b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
@@ -2,8 +2,8 @@
<configuration default="false" name="All in bridge" type="JUnit" factoryName="JUnit" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bridge" />
- <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
- <option name="ALTERNATIVE_JRE_PATH" value="1.7" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index e24b3d5..86d8da3 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -4,10 +4,15 @@
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import android.graphics.BidiRenderer;
+import android.graphics.Paint;
+import android.graphics.Paint_Delegate;
+import android.graphics.RectF;
import android.text.StaticLayout.LineBreaks;
import android.text.Primitive.PrimitiveType;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import com.ibm.icu.text.BreakIterator;
@@ -33,7 +38,7 @@
new DelegateManager<Builder>(Builder.class);
@LayoutlibDelegate
- /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
+ /*package*/ static int nComputeLineBreaks(long nativeBuilder,
int length, float firstWidth, int firstWidthLineCount, float restWidth,
int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
@@ -41,7 +46,7 @@
Builder builder = sBuilderManager.getDelegate(nativeBuilder);
// compute all possible breakpoints.
BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
- it.setText(new Segment(inputText, 0, length));
+ it.setText(new Segment(builder.mText, 0, length));
// average word length in english is 5. So, initialize the possible breaks with a guess.
List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
int loc;
@@ -52,7 +57,7 @@
LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
- List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks);
+ List<Primitive> primitives = computePrimitives(builder.mText, builder.mWidths, length, breaks);
LineBreaker lineBreaker;
if (optimize) {
lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator);
@@ -119,16 +124,62 @@
}
@LayoutlibDelegate
- /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+ /*package*/ static void nSetLocale(long nativeBuilder, String locale) {
Builder builder = sBuilderManager.getDelegate(nativeBuilder);
builder.mLocale = locale;
}
+ @LayoutlibDelegate
+ /*package*/ static void nSetText(long nativeBuilder, char[] text, int length) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ builder.mText = text;
+ builder.mWidths = new float[length];
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static float nAddStyleRun(long nativeBuilder, long nativePaint, long nativeTypeface,
+ int start, int end, boolean isRtl) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+
+ int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
+ return measureText(nativePaint, builder.mText, start, end - start, builder.mWidths, bidiFlags);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddMeasuredRun(long nativeBuilder, int start, int end, float[] widths) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ System.arraycopy(widths, start, builder.mWidths, start, end - start);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddReplacementRun(long nativeBuilder, int start, int end, float width) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ builder.mWidths[start] = width;
+ Arrays.fill(builder.mWidths, start + 1, end, 0.0f);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nGetWidths(long nativeBuilder, float[] floatsArray) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ System.arraycopy(builder.mWidths, 0, floatsArray, 0, builder.mWidths.length);
+ }
+
+ private static float measureText(long nativePaint, char []text, int index, int count,
+ float[] widths, int bidiFlags) {
+ Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
+ RectF bounds = new BidiRenderer(null, paint, text)
+ .renderText(index, index + count, bidiFlags, widths, 0, false);
+ return bounds.right - bounds.left;
+ }
+
/**
- * Java representation of the native Builder class. It currently only stores the locale
- * set by nBuilderSetLocale.
+ * Java representation of the native Builder class.
*/
static class Builder {
String mLocale;
+ char[] mText;
+ float[] mWidths;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 6282fe5..085df85 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -150,4 +150,9 @@
public boolean isDeviceIdleMode() throws RemoteException {
return false;
}
+
+ @Override
+ public boolean isScreenBrightnessBoosted() throws RemoteException {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
index 491dee8..0f37fce 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
@@ -34,6 +34,10 @@
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_6
+ targetCompatibility JavaVersion.VERSION_1_6
+ }
}
dependencies {
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
new file mode 100644
index 0000000..1ca7e01
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
index e29e490..ceb56bf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
index 4ae0da7..c363055 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
index 6729eb4..edda3de 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
index 985d267..d252462 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
index 5142ca6..9bab801 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
index cb52ba5..7ad8605 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
index 5290cf6..e9e0a33 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
index 49b1df6..d109302 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
index 85b2029..816ecc8 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
index 428fdf4..b034b75 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
index 027d5d3..f86b1d3 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
index c7d64f8..8bbae90 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
index 8831b71..8af745d 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
index e13ad72..d7e5486 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
@@ -56,7 +56,7 @@
private static final int THUMBNAIL_SIZE = 250;
- private static final double MAX_PERCENT_DIFFERENCE = 0.1;
+ private static final double MAX_PERCENT_DIFFERENCE = 0.3;
public static void requireSimilar(@NonNull String relativePath, @NonNull BufferedImage image)
throws IOException {
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
index d929f55..90f66c4 100644
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ b/wifi/java/android/net/wifi/IRttManager.aidl
@@ -15,8 +15,8 @@
*/
package android.net.wifi;
-
import android.os.Messenger;
+import android.net.wifi.RttManager;
/**
* {@hide}
@@ -24,4 +24,5 @@
interface IRttManager
{
Messenger getMessenger();
+ RttManager.RttCapabilities getRttCapabilities();
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bc95a36..5342494 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -155,6 +155,10 @@
void setAllowScansWithTraffic(int enabled);
+ boolean getAllowScansWhileAssociated();
+
+ void setAllowScansWhileAssociated(boolean enabled);
+
WifiConnectionStatistics getConnectionStatistics();
void disableEphemeralNetwork(String SSID);
diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl
new file mode 100644
index 0000000..5c6d447
--- /dev/null
+++ b/wifi/java/android/net/wifi/RttManager.aidl
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015, 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.wifi;
+parcelable RttManager.RttCapabilities;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 57343c5..65ecf5d 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -26,10 +26,19 @@
private static final boolean DBG = true;
private static final String TAG = "RttManager";
- public static final int RTT_TYPE_UNSPECIFIED = 0;
- public static final int RTT_TYPE_ONE_SIDED = 1;
- public static final int RTT_TYPE_11_V = 2;
- public static final int RTT_TYPE_11_MC = 4;
+ /** @deprecated Type must be specified*/
+ @Deprecated
+ public static final int RTT_TYPE_UNSPECIFIED = 0;
+ public static final int RTT_TYPE_ONE_SIDED = 1;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_V = 2;
+ public static final int RTT_TYPE_TWO_SIDED = 4;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_MC = 4;
public static final int RTT_PEER_TYPE_UNSPECIFIED = 0;
public static final int RTT_PEER_TYPE_AP = 1;
@@ -42,6 +51,9 @@
public static final int RTT_CHANNEL_WIDTH_80P80 = 4;
public static final int RTT_CHANNEL_WIDTH_5 = 5;
public static final int RTT_CHANNEL_WIDTH_10 = 6;
+
+ /** @deprecated channel info must be specified*/
+ @Deprecated
public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
public static final int RTT_STATUS_SUCCESS = 0;
@@ -53,6 +65,12 @@
public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6;
public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7;
public static final int RTT_STATUS_ABORTED = 8;
+ //if the T1-T4 or TOD/TOA Timestamp is illegal
+ public static final int RTT_STATUS_FAIL_INVALID_TS = 9;
+ //11mc protocol failed, eg, unrecognized FTMR/FTM
+ public static final int RTT_STATUS_FAIL_PROTOCOL = 10;
+ public static final int RTT_STATUS_FAIL_SCHEDULE = 11;
+ public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12;
public static final int REASON_UNSPECIFIED = -1;
public static final int REASON_NOT_AVAILABLE = -2;
@@ -61,41 +79,269 @@
public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ /**
+ * RTT BW supported bit mask
+ */
+ public static final int RTT_BW_5_SUPPORT = 0x1;
+ public static final int RTT_BW_10_SUPPORT = 0x2;
+ public static final int RTT_BW_20_SUPPORT = 0x4;
+ public static final int RTT_BW_40_SUPPORT = 0x8;
+ public static final int RTT_BW_80_SUPPORT = 0x10;
+ public static final int RTT_BW_160_SUPPORT = 0x20;
+
+ /**
+ * RTT Preamble Support bit mask
+ */
+ public static final int PREAMBLE_LEGACY = 0x1;
+ public static final int PREAMBLE_HT = 0x2;
+ public static final int PREAMBLE_VHT = 0x4;
+
+ /** @deprecated It has been replaced by RttCapabilities*/
+ @Deprecated
public class Capabilities {
public int supportedType;
public int supportedPeerType;
}
+ /** @deprecated It has been replaced by getRttCapabilities*/
+ @Deprecated
public Capabilities getCapabilities() {
return new Capabilities();
}
+ /**
+ * This class describe the RTT capability of the Hardware
+ */
+ public static class RttCapabilities implements Parcelable {
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedType;
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedPeerType;
+ //1-sided rtt measurement is supported
+ public boolean oneSidedRttSupported;
+ //11mc 2-sided rtt measurement is supported
+ public boolean twoSided11McRttSupported;
+ //location configuration information supported
+ public boolean lciSupported;
+ //location civic records supported
+ public boolean lcrSupported;
+ //preamble supported, see bit mask definition above
+ public int preambleSupported;
+ //RTT bandwidth supported
+ public int bwSupported;
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("oneSidedRtt ").
+ append(oneSidedRttSupported ? "is Supported. " : "is not supported. ").
+ append("twoSided11McRtt ").
+ append(twoSided11McRttSupported ? "is Supported. " : "is not supported. ").
+ append("lci ").
+ append(lciSupported ? "is Supported. " : "is not supported. ").
+ append("lcr ").
+ append(lcrSupported ? "is Supported. " : "is not supported. ");
+
+ if ((preambleSupported & PREAMBLE_LEGACY) != 0) {
+ sb.append("Legacy ");
+ }
+
+ if ((preambleSupported & PREAMBLE_HT) != 0) {
+ sb.append("HT ");
+ }
+
+ if ((preambleSupported & PREAMBLE_VHT) != 0) {
+ sb.append("VHT ");
+ }
+
+ sb.append("is supported. \n");
+
+ if ((bwSupported & RTT_BW_5_SUPPORT) != 0) {
+ sb.append("5 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_10_SUPPORT) != 0) {
+ sb.append("10 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_20_SUPPORT) != 0) {
+ sb.append("20 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_40_SUPPORT) != 0) {
+ sb.append("40 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_80_SUPPORT) != 0) {
+ sb.append("80 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_160_SUPPORT) != 0) {
+ sb.append("160 MHz ");
+ }
+
+ sb.append("is supported.");
+
+ return sb.toString();
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(oneSidedRttSupported ? 1 : 0);
+ dest.writeInt(twoSided11McRttSupported ? 1 : 0);
+ dest.writeInt(lciSupported ? 1 : 0);
+ dest.writeInt(lcrSupported ? 1 : 0);
+ dest.writeInt(preambleSupported);
+ dest.writeInt(bwSupported);
+
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<RttCapabilities> CREATOR =
+ new Creator<RttCapabilities>() {
+ public RttCapabilities createFromParcel(Parcel in) {
+ RttCapabilities capabilities = new RttCapabilities();
+ capabilities.oneSidedRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.twoSided11McRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.lciSupported = in.readInt() == 1 ? true : false;
+ capabilities.lcrSupported = in.readInt() == 1 ? true : false;
+ capabilities.preambleSupported = in.readInt();
+ capabilities.bwSupported = in.readInt();
+ return capabilities;
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public RttCapabilities[] newArray(int size) {
+ return new RttCapabilities[size];
+ }
+ };
+ }
+
+ public RttCapabilities getRttCapabilities() {
+ synchronized (sCapabilitiesLock) {
+ if (mRttCapabilities == null) {
+ try {
+ mRttCapabilities = mService.getRttCapabilities();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can not get RTT Capabilities");
+ }
+ }
+ return mRttCapabilities;
+ }
+ }
+
/** specifies parameters for RTT request */
public static class RttParams {
-
- /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
+ /**
+ * type of destination device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA
+ */
public int deviceType;
- /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
- * RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
+ /**
+ * type of RTT measurement method; one of RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED.
+ */
public int requestType;
/** mac address of the device being ranged */
public String bssid;
- /** channel frequency that the device is on; optional */
+ /**
+ * The primary 20 MHz frequency (in MHz) of the channel over which the client is
+ * communicating with the access point.Similar as ScanResult.frequency
+ */
public int frequency;
- /** optional channel width. wider channels result in better accuracy,
- * but they take longer time, and even get aborted may times; use
- * RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
+ /**
+ * channel width used for RTT measurement. User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase. Similar as ScanResult.channelWidth
+ */
public int channelWidth;
- /** number of samples to be taken */
+ /**
+ * Not used if the AP bandwidth is 20 MHz
+ * If the AP use 40, 80 or 160 MHz, this is the center frequency
+ * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+ * similar as ScanResult.centerFreq0
+ */
+ public int centerFreq0;
+
+ /**
+ * Only used if the AP bandwidth is 80 + 80 MHz
+ * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+ * similar as ScanResult.centerFreq1
+ */
+ public int centerFreq1;
+ /**
+ * number of samples to be taken
+ * @deprecated It has been replaced by numSamplesPerBurst
+ */
+ @Deprecated
public int num_samples;
- /** number of retries if a sample fails */
+ /**
+ * number of retries if a sample fails
+ * @deprecated It has been replaced by numRetriesPerMeasurementFrame
+ */
+ @Deprecated
public int num_retries;
+
+ /** Number of burst. fixed to 1 for single side RTT*/
+ public int numberBurst;
+
+ /** valid only if numberBurst > 1, interval between burst(ms). Not used by singe side RTT */
+ public int interval;
+
+ /** number of samples to be taken in one burst*/
+ public int numSamplesPerBurst;
+
+ /** number of retries for each measurement frame if a sample fails
+ * Only used by single side RTT
+ */
+ public int numRetriesPerMeasurementFrame;
+
+ /** number of retries for FTMR frame if fails Only used by 80211MC double side RTT */
+ public int numRetriesPerFTMR;
+
+ /** Request LCI information */
+ public boolean LCIRequest;
+
+ /** Request LCR information */
+ public boolean LCRRequest;
+
+ /** Timeout for each burst, unit of 250 us*/
+ public int burstTimeout;
+
+ /** preamble used for RTT measurement
+ * should be one of PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+ */
+ public int preamble;
+
+ /** bandWidth used for RTT measurement.User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase too.
+ * should be one of RTT_CHANNEL_WIDTH_20 to RTT_CHANNEL_WIDTH_80
+ */
+ public int bandwidth;
+
+ public RttParams() {
+ //provide initial value for RttParams
+ deviceType = RTT_PEER_TYPE_AP;
+ numberBurst = 1;
+ numSamplesPerBurst = 8;
+ numRetriesPerMeasurementFrame = 0;
+ burstTimeout = 40 + numSamplesPerBurst *4;
+ preamble = PREAMBLE_LEGACY;
+ bandwidth = RTT_CHANNEL_WIDTH_20;
+ }
}
/** pseudo-private class used to parcel arguments */
@@ -121,10 +367,20 @@
dest.writeInt(params.deviceType);
dest.writeInt(params.requestType);
dest.writeString(params.bssid);
- dest.writeInt(params.frequency);
dest.writeInt(params.channelWidth);
- dest.writeInt(params.num_samples);
- dest.writeInt(params.num_retries);
+ dest.writeInt(params.frequency);
+ dest.writeInt(params.centerFreq0);
+ dest.writeInt(params.centerFreq1);
+ dest.writeInt(params.numberBurst);
+ dest.writeInt(params.interval);
+ dest.writeInt(params.numSamplesPerBurst);
+ dest.writeInt(params.numRetriesPerMeasurementFrame);
+ dest.writeInt(params.numRetriesPerFTMR);
+ dest.writeInt(params.LCIRequest ? 1 : 0);
+ dest.writeInt(params.LCRRequest ? 1 : 0);
+ dest.writeInt(params.burstTimeout);
+ dest.writeInt(params.preamble);
+ dest.writeInt(params.bandwidth);
}
} else {
dest.writeInt(0);
@@ -148,11 +404,20 @@
params[i].deviceType = in.readInt();
params[i].requestType = in.readInt();
params[i].bssid = in.readString();
- params[i].frequency = in.readInt();
params[i].channelWidth = in.readInt();
- params[i].num_samples = in.readInt();
- params[i].num_retries = in.readInt();
-
+ params[i].frequency = in.readInt();
+ params[i].centerFreq0 = in.readInt();
+ params[i].centerFreq1 = in.readInt();
+ params[i].numberBurst = in.readInt();
+ params[i].interval = in.readInt();
+ params[i].numSamplesPerBurst = in.readInt();
+ params[i].numRetriesPerMeasurementFrame = in.readInt();
+ params[i].numRetriesPerFTMR = in.readInt();
+ params[i].LCIRequest = in.readInt() == 1 ? true : false;
+ params[i].LCRRequest = in.readInt() == 1 ? true : false;
+ params[i].burstTimeout = in.readInt();
+ params[i].preamble = in.readInt();
+ params[i].bandwidth = in.readInt();
}
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
@@ -165,46 +430,143 @@
};
}
+ public class wifiInformationElement {
+ /** Information Element ID*/
+ public int id;
+ public String data;
+ }
/** specifies RTT results */
public static class RttResult {
/** mac address of the device being ranged */
public String bssid;
+ /** # of burst for this measurement*/
+ public int burstNumber;
+
+ /** total number of measurement frames in this measurement*/
+ public int measurementFrameNumber;
+
+ /** total successful number of measurement frames in this measurement*/
+ public int successMeasurementFrameNumber;
+
+ /** Maximum number of frames per burst supported by peer */
+ public int frameNumberPerBurstPeer;
+
/** status of the request */
public int status;
- /** type of the request used */
+ /**
+ * type of the request used
+ * @deprecated It has been replaced by measurementType
+ */
+ @Deprecated
public int requestType;
+ /** RTT measurement method type used, shoudl be one of RTT_TYPE_ONE_SIDED or
+ * RTT_TYPE_TWO_SIDED.
+ */
+ public int measurementType;
+
+ /** please retry RTT measurement after this S since peer indicate busy at ths moment*/
+ public int retryAfterDuration;
+
/** timestamp of completion, in microsecond since boot */
public long ts;
- /** average RSSI observed */
+ /** average RSSI observed, unit of 0.5 dB */
public int rssi;
- /** RSSI spread (i.e. max - min) */
+ /**
+ * RSSI spread (i.e. max - min)
+ * @deprecated It has been replaced by rssi_spread
+ */
+ @Deprecated
public int rssi_spread;
- /** average transmit rate */
+ /**RSSI spread (i.e. max - min), unit of 0.5 dB */
+ public int rssiSpread;
+
+ /**
+ * average transmit rate
+ * @deprecated It has been replaced by txRate
+ */
+ @Deprecated
public int tx_rate;
- /** average round trip time in nano second */
+ /** average transmit rate */
+ public int txRate;
+
+ /** average receiving rate */
+ public int rxRate;
+
+ /**
+ * average round trip time in nano second
+ * @deprecated It has been replaced by rtt
+ */
+ @Deprecated
public long rtt_ns;
- /** standard deviation observed in round trip time */
+ /** average round trip time in 0.1 nano second */
+ public long rtt;
+
+ /**
+ * standard deviation observed in round trip time
+ * @deprecated It has been replaced by rttStandardDeviation
+ */
+ @Deprecated
public long rtt_sd_ns;
- /** spread (i.e. max - min) round trip time */
+ /** standard deviation of RTT in 0.1 ns */
+ public long rttStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) round trip time
+ * @deprecated It has been replaced by rttSpread
+ */
+ @Deprecated
public long rtt_spread_ns;
- /** average distance in centimeter, computed based on rtt_ns */
+ /** spread (i.e. max - min) RTT in 0.1 ns */
+ public long rttSpread;
+
+ /**
+ * average distance in centimeter, computed based on rtt_ns
+ * @deprecated It has been replaced by distance
+ */
+ @Deprecated
public int distance_cm;
- /** standard deviation observed in distance */
+ /** average distance in cm, computed based on rtt */
+ public int distance;
+
+ /**
+ * standard deviation observed in distance
+ * @deprecated It has been replaced with distanceStandardDeviation
+ */
+ @Deprecated
public int distance_sd_cm;
- /** spread (i.e. max - min) distance */
+ /** standard deviation observed in distance in cm*/
+ public int distanceStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) distance
+ * @deprecated It has been replaced by distanceSpread
+ */
+ @Deprecated
public int distance_spread_cm;
+
+ /** spread (i.e. max - min) distance in cm */
+ public int distanceSpread;
+
+ /** the duration of this measurement burst*/
+ public int burstDuration;
+
+ /** LCI information Element*/
+ wifiInformationElement LCI;
+
+ /** LCR information Element*/
+ wifiInformationElement LCR;
}
@@ -228,18 +590,28 @@
dest.writeInt(mResults.length);
for (RttResult result : mResults) {
dest.writeString(result.bssid);
+ dest.writeInt(result.burstNumber);
+ dest.writeInt(result.measurementFrameNumber);
+ dest.writeInt(result.successMeasurementFrameNumber);
+ dest.writeInt(result.frameNumberPerBurstPeer);
dest.writeInt(result.status);
- dest.writeInt(result.requestType);
+ dest.writeInt(result.measurementType);
+ dest.writeInt(result.retryAfterDuration);
dest.writeLong(result.ts);
dest.writeInt(result.rssi);
- dest.writeInt(result.rssi_spread);
- dest.writeInt(result.tx_rate);
- dest.writeLong(result.rtt_ns);
- dest.writeLong(result.rtt_sd_ns);
- dest.writeLong(result.rtt_spread_ns);
- dest.writeInt(result.distance_cm);
- dest.writeInt(result.distance_sd_cm);
- dest.writeInt(result.distance_spread_cm);
+ dest.writeInt(result.rssiSpread);
+ dest.writeInt(result.txRate);
+ dest.writeLong(result.rtt);
+ dest.writeLong(result.rttStandardDeviation);
+ dest.writeLong(result.rttSpread);
+ dest.writeInt(result.distance);
+ dest.writeInt(result.distanceStandardDeviation);
+ dest.writeInt(result.distanceSpread);
+ dest.writeInt(result.burstDuration);
+ //dest.writeInt(result.LCI.id);
+ //dest.writeString(result.LCI.data);
+ //dest.writeInt(result.LCR.id);
+ //dest.writeString(result.LCR.data);
}
} else {
dest.writeInt(0);
@@ -261,18 +633,28 @@
for (int i = 0; i < num; i++) {
results[i] = new RttResult();
results[i].bssid = in.readString();
+ results[i].burstNumber = in.readInt();
+ results[i].measurementFrameNumber = in.readInt();
+ results[i].successMeasurementFrameNumber = in.readInt();
+ results[i].frameNumberPerBurstPeer = in.readInt();
results[i].status = in.readInt();
- results[i].requestType = in.readInt();
+ results[i].measurementType = in.readInt();
+ results[i].retryAfterDuration = in.readInt();
results[i].ts = in.readLong();
results[i].rssi = in.readInt();
- results[i].rssi_spread = in.readInt();
- results[i].tx_rate = in.readInt();
- results[i].rtt_ns = in.readLong();
- results[i].rtt_sd_ns = in.readLong();
- results[i].rtt_spread_ns = in.readLong();
- results[i].distance_cm = in.readInt();
- results[i].distance_sd_cm = in.readInt();
- results[i].distance_spread_cm = in.readInt();
+ results[i].rssiSpread = in.readInt();
+ results[i].txRate = in.readInt();
+ results[i].rtt = in.readLong();
+ results[i].rttStandardDeviation = in.readLong();
+ results[i].rttSpread = in.readLong();
+ results[i].distance = in.readInt();
+ results[i].distanceStandardDeviation = in.readInt();
+ results[i].distanceSpread = in.readInt();
+ results[i].burstDuration = in.readInt();
+ //results[i].LCI.id = in.readInt();
+ //results[i].LCI.data = in.readString();
+ //results[i].LCR.id = in.readInt();
+ //results[i].LCR.data = in.readString();
}
ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -292,7 +674,70 @@
public void onAborted();
}
+ private boolean rttParamSanity(RttParams params, int index) {
+ if (mRttCapabilities == null) {
+ if(getRttCapabilities() == null) {
+ Log.e(TAG, "Can not get RTT capabilities");
+ //throw new IllegalStateException("RTT chip is not working");
+ }
+ }
+
+ if (params.deviceType != RTT_PEER_TYPE_AP) {
+ return false;
+ } else if (params.requestType != RTT_TYPE_ONE_SIDED && params.requestType !=
+ RTT_TYPE_TWO_SIDED) {
+ Log.e(TAG, "Request " + index + ": Illegal Request Type: " + params.requestType);
+ return false;
+ } else if (params.requestType == RTT_TYPE_ONE_SIDED &&
+ !mRttCapabilities.oneSidedRttSupported) {
+ Log.e(TAG, "Request " + index + ": One side RTT is not supported");
+ return false;
+ } else if (params.requestType == RTT_TYPE_TWO_SIDED &&
+ !mRttCapabilities.twoSided11McRttSupported) {
+ Log.e(TAG, "Request " + index + ": two side RTT is not supported");
+ return false;
+ } else if ( params.numberBurst <= 0 ) {
+ Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst);
+ return false;
+ } else if (params.numberBurst > 1 && params.interval <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal interval value: " + params.interval);
+ return false;
+ } else if (params.numSamplesPerBurst <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " +
+ params.numSamplesPerBurst);
+ return false;
+ } else if (params.numRetriesPerMeasurementFrame < 0 || params.numRetriesPerFTMR < 0) {
+ Log.e(TAG, "Request " + index + ": Illegal retry number");
+ return false;
+ } else if (params.LCIRequest && !mRttCapabilities.lciSupported) {
+ Log.e(TAG, "Request " + index + ": LCI is not supported");
+ return false;
+ } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) {
+ Log.e(TAG, "Request " + index + ": LCR is not supported");
+ return false;
+ } else if (params.burstTimeout <= 0){
+ Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout);
+ return false;
+ } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this preamble: " + params.preamble);
+ return false;
+ } else if ((params.bandwidth & mRttCapabilities.bwSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this bandwidth: " + params.bandwidth);
+ return false;
+ }
+
+ return true;
+ }
+
public void startRanging(RttParams[] params, RttListener listener) {
+ int index = 0;
+ for(RttParams rttParam : params) {
+ if (!rttParamSanity(rttParam, index)) {
+ throw new IllegalArgumentException("RTT Request Parameter Illegal");
+ }
+ index++;
+ }
+
validateChannel();
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
@@ -315,12 +760,14 @@
private Context mContext;
private IRttManager mService;
+ private RttCapabilities mRttCapabilities;
private static final int INVALID_KEY = 0;
private static int sListenerKey = 1;
private static final SparseArray sListenerMap = new SparseArray();
private static final Object sListenerMapLock = new Object();
+ private static final Object sCapabilitiesLock = new Object();
private static AsyncChannel sAsyncChannel;
private static CountDownLatch sConnected;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index b4f4927..e8a51e3 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,8 +16,6 @@
package android.net.wifi;
-import android.net.wifi.passpoint.WifiPasspointInfo;
-import android.net.wifi.passpoint.WifiPasspointManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -215,11 +213,19 @@
public int distanceSdCm;
/**
- * Passpoint ANQP information. This is not fetched automatically.
- * Use {@link WifiPasspointManager#requestAnqpInfo} to request ANQP info.
- * {@hide}
+ * Indicates if the scan result represents a passpoint AP
*/
- public WifiPasspointInfo passpoint;
+ public boolean passpointNetwork;
+
+ /**
+ * Indicates if venue name
+ */
+ public String venueName;
+
+ /**
+ * Indicates operator name
+ */
+ public String operatorFriendlyName;
/**
* {@hide}
@@ -292,6 +298,7 @@
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
}
/** {@hide} */
@@ -310,6 +317,7 @@
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
}
/** {@hide} */
@@ -329,6 +337,7 @@
this.centerFreq0 = centerFreq0;
this.centerFreq1 = centerFreq1;
this.is80211McRTTResponder = is80211McRTTResponder;
+ this.passpointNetwork = false;
}
/** copy constructor {@hide} */
@@ -348,13 +357,15 @@
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
seen = source.seen;
- passpoint = source.passpoint;
autoJoinStatus = source.autoJoinStatus;
untrusted = source.untrusted;
numConnection = source.numConnection;
numUsage = source.numUsage;
numIpConfigFailures = source.numIpConfigFailures;
isAutoJoinCandidate = source.isAutoJoinCandidate;
+ passpointNetwork = source.passpointNetwork;
+ venueName = source.venueName;
+ operatorFriendlyName = source.operatorFriendlyName;
}
}
@@ -388,7 +399,7 @@
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
append("(cm)");
- sb.append(", passpoint: ").append(passpoint != null ? "yes" : "no");
+ sb.append(", passpoint: ").append(passpointNetwork ? "yes" : "no");
if (autoJoinStatus != 0) {
sb.append(", status: ").append(autoJoinStatus);
}
@@ -431,12 +442,10 @@
dest.writeInt(numUsage);
dest.writeInt(numIpConfigFailures);
dest.writeInt(isAutoJoinCandidate);
- if (passpoint != null) {
- dest.writeInt(1);
- passpoint.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
+ dest.writeInt(passpointNetwork ? 1 : 0);
+ dest.writeString(venueName);
+ dest.writeString(operatorFriendlyName);
+
if (informationElements != null) {
dest.writeInt(informationElements.length);
for (int i = 0; i < informationElements.length; i++) {
@@ -478,9 +487,9 @@
sr.numUsage = in.readInt();
sr.numIpConfigFailures = in.readInt();
sr.isAutoJoinCandidate = in.readInt();
- if (in.readInt() == 1) {
- sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in);
- }
+ sr.passpointNetwork = in.readInt() == 1;
+ sr.venueName = in.readString();
+ sr.operatorFriendlyName = in.readString();
int n = in.readInt();
if (n != 0) {
sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 6263463..9284796 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -26,12 +26,35 @@
* @hide
*/
public final class WifiActivityEnergyInfo implements Parcelable {
- private final long mTimestamp;
- private final int mStackState;
- private final int mControllerTxTimeMs;
- private final int mControllerRxTimeMs;
- private final int mControllerIdleTimeMs;
- private final int mControllerEnergyUsed;
+ /**
+ * @hide
+ */
+ public long mTimestamp;
+
+ /**
+ * @hide
+ */
+ public int mStackState;
+
+ /**
+ * @hide
+ */
+ public int mControllerTxTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerRxTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerIdleTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerEnergyUsed;
public static final int STACK_STATE_INVALID = 0;
public static final int STACK_STATE_STATE_ACTIVE = 1;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7e04f2b..11bdebb 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -973,13 +973,18 @@
}
}
- if (FQDN != null) {
- /* must have a providerFriendlyName */
- if (providerFriendlyName == null) {
+ if (TextUtils.isEmpty(FQDN) == false) {
+ /* this is passpoint configuration; it must not have an SSID */
+ if (TextUtils.isEmpty(SSID) == false) {
+ return false;
+ }
+ /* this is passpoint configuration; it must have a providerFriendlyName */
+ if (TextUtils.isEmpty(providerFriendlyName)) {
return false;
}
/* this is passpoint configuration; it must have enterprise config */
- if (enterpriseConfig == null) {
+ if (enterpriseConfig == null
+ || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
return false;
}
}
@@ -989,6 +994,16 @@
}
/**
+ * Identify if this configuration represents a passpoint network
+ */
+ public boolean isPasspoint() {
+ return !TextUtils.isEmpty(FQDN)
+ && !TextUtils.isEmpty(providerFriendlyName)
+ && enterpriseConfig != null
+ && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+ }
+
+ /**
* Helper function, identify if a configuration is linked
* @hide
*/
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b292c22..e1460ef 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2598,6 +2598,27 @@
}
}
+ /**
+ * Set setting for allowing Scans when infrastructure is associated
+ * @hide
+ */
+ public void setAllowScansWhileAssociated(boolean enabled) {
+ try {
+ mService.setAllowScansWhileAssociated(enabled);
+ } catch (RemoteException e) {
+ }
+ }
+ /**
+ * Get setting for allowing Scans when infrastructure is associated
+ * @hide
+ */
+ public boolean getAllowScansWhileAssociated() {
+ try {
+ return mService.getAllowScansWhileAssociated();
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index b9b17eb..0245a3d 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -262,7 +262,7 @@
for (ScanResult sr : mAnqpRequest)
if (sr.BSSID.equals(result.bssid)) {
Log.d(TAG, "find hit " + result.bssid);
- sr.passpoint = result;
+ /* sr.passpoint = result; */
mAnqpRequest.remove(sr);
Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
break;