Merge "Camera2 framework stress test suite"
diff --git a/Android.mk b/Android.mk
index 1d797c4..ad164e20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -187,6 +187,8 @@
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
+ core/java/android/hardware/location/IContextHubCallback.aidl \
+ core/java/android/hardware/location/IContextHubService.aidl \
core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
@@ -288,6 +290,7 @@
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IEphemeralResolver.aidl \
core/java/com/android/internal/app/IProcessStats.aidl \
+ core/java/com/android/internal/app/ISoundTriggerService.aidl \
core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
core/java/com/android/internal/app/IVoiceInteractor.aidl \
@@ -330,10 +333,10 @@
location/java/android/location/IFusedProvider.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
+ location/java/android/location/IGnssStatusListener.aidl \
+ location/java/android/location/IGnssStatusProvider.aidl \
location/java/android/location/IGpsMeasurementsListener.aidl \
location/java/android/location/IGpsNavigationMessageListener.aidl \
- location/java/android/location/IGpsStatusListener.aidl \
- location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
location/java/android/location/ILocationManager.aidl \
location/java/android/location/IFusedGeofenceHardware.aidl \
@@ -384,6 +387,8 @@
media/java/android/media/tv/ITvInputSessionCallback.aidl \
media/java/android/service/media/IMediaBrowserService.aidl \
media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl \
+ telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl \
+ telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl \
telecomm/java/com/android/internal/telecom/IVideoCallback.aidl \
telecomm/java/com/android/internal/telecom/IVideoProvider.aidl \
telecomm/java/com/android/internal/telecom/IConnectionService.aidl \
@@ -414,6 +419,7 @@
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
+ telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index a10c510..24776c1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33,6 +33,7 @@
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -505,6 +506,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -880,6 +883,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1127,6 +1131,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -2619,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2677,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4636,6 +4655,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5532,6 +5552,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5548,6 +5569,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5788,6 +5810,7 @@
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+ method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
@@ -5814,6 +5837,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5883,6 +5907,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6294,7 +6319,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6303,9 +6327,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -6509,8 +6530,9 @@
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
- field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
}
@@ -9947,7 +9969,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9956,13 +9978,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10066,6 +10093,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10125,6 +10157,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10160,6 +10193,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
@@ -13356,6 +13390,7 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
+ method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isWakeUpSensor();
@@ -13370,11 +13405,13 @@
field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
@@ -13382,6 +13419,7 @@
field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+ field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13393,11 +13431,13 @@
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEART_BEAT = 31; // 0x1f
field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_LIGHT = 5; // 0x5
field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+ field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
field public static final int TYPE_POSE_6DOF = 28; // 0x1c
field public static final int TYPE_PRESSURE = 6; // 0x6
@@ -13405,11 +13445,27 @@
field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+ field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
field public static final int TYPE_STEP_COUNTER = 19; // 0x13
field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
}
+ public class SensorAdditionalInfo {
+ field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+ field public static final int TYPE_FRAME_END = 1; // 0x1
+ field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+ field public static final int TYPE_SAMPLING = 65540; // 0x10004
+ field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+ field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+ field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+ field public final float[] floatValues;
+ field public final int[] intValues;
+ field public final android.hardware.Sensor sensor;
+ field public final int serial;
+ field public final int type;
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -13417,6 +13473,14 @@
field public final float[] values;
}
+ public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+ ctor public SensorEventCallback();
+ method public void onAccuracyChanged(android.hardware.Sensor, int);
+ method public void onFlushCompleted(android.hardware.Sensor);
+ method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+ method public void onSensorChanged(android.hardware.SensorEvent);
+ }
+
public abstract interface SensorEventListener {
method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13438,6 +13502,7 @@
method public static void getAngleChange(float[], float[], float[]);
method public android.hardware.Sensor getDefaultSensor(int);
method public android.hardware.Sensor getDefaultSensor(int, boolean);
+ method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
method public static float getInclination(float[]);
method public static float[] getOrientation(float[], float[]);
method public static void getQuaternionFromVector(float[], float[]);
@@ -13445,6 +13510,8 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13453,6 +13520,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13517,6 +13585,12 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
+ public static abstract class SensorManager.DynamicSensorConnectionCallback {
+ ctor public SensorManager.DynamicSensorConnectionCallback();
+ method public void onDynamicSensorConnected(android.hardware.Sensor);
+ method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+ }
+
public final class TriggerEvent {
field public android.hardware.Sensor sensor;
field public long timestamp;
@@ -19017,6 +19091,288 @@
method public static boolean isPresent();
}
+ public abstract interface GnssNmeaListener {
+ method public abstract void onNmeaReceived(long, java.lang.String);
+ }
+
+ public final class GnssStatus {
+ method public float getAzimuth(int);
+ method public int getConstellationType(int);
+ method public float getElevation(int);
+ method public int getNumSatellites();
+ method public int getPrn(int);
+ method public float getSnr(int);
+ method public boolean hasAlmanac(int);
+ method public boolean hasEphemeris(int);
+ method public boolean usedInFix(int);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract class GnssStatusCallback {
+ ctor public GnssStatusCallback();
+ method public void onFirstFix(int);
+ method public void onSatelliteStatusChanged(android.location.GnssStatus);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class GpsClock implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getBiasInNs();
+ method public double getBiasUncertaintyInNs();
+ method public double getDriftInNsPerSec();
+ method public double getDriftUncertaintyInNsPerSec();
+ method public long getFullBiasInNs();
+ method public short getLeapSecond();
+ method public long getTimeInNs();
+ method public long getTimeOfLastHwClockDiscontinuityInNs();
+ method public double getTimeUncertaintyInNs();
+ method public byte getType();
+ method public boolean hasBiasInNs();
+ method public boolean hasBiasUncertaintyInNs();
+ method public boolean hasDriftInNsPerSec();
+ method public boolean hasDriftUncertaintyInNsPerSec();
+ method public boolean hasFullBiasInNs();
+ method public boolean hasLeapSecond();
+ method public boolean hasTimeUncertaintyInNs();
+ method public void reset();
+ method public void resetBiasInNs();
+ method public void resetBiasUncertaintyInNs();
+ method public void resetDriftInNsPerSec();
+ method public void resetDriftUncertaintyInNsPerSec();
+ method public void resetFullBiasInNs();
+ method public void resetLeapSecond();
+ method public void resetTimeUncertaintyInNs();
+ method public void set(android.location.GpsClock);
+ method public void setBiasInNs(double);
+ method public void setBiasUncertaintyInNs(double);
+ method public void setDriftInNsPerSec(double);
+ method public void setDriftUncertaintyInNsPerSec(double);
+ method public void setFullBiasInNs(long);
+ method public void setLeapSecond(short);
+ method public void setTimeInNs(long);
+ method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+ method public void setTimeUncertaintyInNs(double);
+ method public void setType(byte);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+ field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+ field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
+ field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+ }
+
+ public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getAccumulatedDeltaRangeInMeters();
+ method public short getAccumulatedDeltaRangeState();
+ method public double getAccumulatedDeltaRangeUncertaintyInMeters();
+ method public double getAzimuthInDeg();
+ method public double getAzimuthUncertaintyInDeg();
+ method public int getBitNumber();
+ method public long getCarrierCycles();
+ method public float getCarrierFrequencyInHz();
+ method public double getCarrierPhase();
+ method public double getCarrierPhaseUncertainty();
+ method public double getCn0InDbHz();
+ method public double getCodePhaseInChips();
+ method public double getCodePhaseUncertaintyInChips();
+ method public double getDopplerShiftInHz();
+ method public double getDopplerShiftUncertaintyInHz();
+ method public double getElevationInDeg();
+ method public double getElevationUncertaintyInDeg();
+ method public byte getLossOfLock();
+ method public byte getMultipathIndicator();
+ method public byte getPrn();
+ method public double getPseudorangeInMeters();
+ method public double getPseudorangeRateCarrierInMetersPerSec();
+ method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
+ method public double getPseudorangeRateInMetersPerSec();
+ method public double getPseudorangeRateUncertaintyInMetersPerSec();
+ method public double getPseudorangeUncertaintyInMeters();
+ method public long getReceivedGpsTowInNs();
+ method public long getReceivedGpsTowUncertaintyInNs();
+ method public double getSnrInDb();
+ method public short getState();
+ method public short getTimeFromLastBitInMs();
+ method public double getTimeOffsetInNs();
+ method public boolean hasAzimuthInDeg();
+ method public boolean hasAzimuthUncertaintyInDeg();
+ method public boolean hasBitNumber();
+ method public boolean hasCarrierCycles();
+ method public boolean hasCarrierFrequencyInHz();
+ method public boolean hasCarrierPhase();
+ method public boolean hasCarrierPhaseUncertainty();
+ method public boolean hasCodePhaseInChips();
+ method public boolean hasCodePhaseUncertaintyInChips();
+ method public boolean hasDopplerShiftInHz();
+ method public boolean hasDopplerShiftUncertaintyInHz();
+ method public boolean hasElevationInDeg();
+ method public boolean hasElevationUncertaintyInDeg();
+ method public boolean hasPseudorangeInMeters();
+ method public boolean hasPseudorangeUncertaintyInMeters();
+ method public boolean hasSnrInDb();
+ method public boolean hasTimeFromLastBitInMs();
+ method public boolean isPseudorangeRateCorrected();
+ method public boolean isUsedInFix();
+ method public void reset();
+ method public void resetAzimuthInDeg();
+ method public void resetAzimuthUncertaintyInDeg();
+ method public void resetBitNumber();
+ method public void resetCarrierCycles();
+ method public void resetCarrierFrequencyInHz();
+ method public void resetCarrierPhase();
+ method public void resetCarrierPhaseUncertainty();
+ method public void resetCodePhaseInChips();
+ method public void resetCodePhaseUncertaintyInChips();
+ method public void resetDopplerShiftInHz();
+ method public void resetDopplerShiftUncertaintyInHz();
+ method public void resetElevationInDeg();
+ method public void resetElevationUncertaintyInDeg();
+ method public void resetPseudorangeInMeters();
+ method public void resetPseudorangeUncertaintyInMeters();
+ method public void resetSnrInDb();
+ method public void resetTimeFromLastBitInMs();
+ method public void set(android.location.GpsMeasurement);
+ method public void setAccumulatedDeltaRangeInMeters(double);
+ method public void setAccumulatedDeltaRangeState(short);
+ method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+ method public void setAzimuthInDeg(double);
+ method public void setAzimuthUncertaintyInDeg(double);
+ method public void setBitNumber(int);
+ method public void setCarrierCycles(long);
+ method public void setCarrierFrequencyInHz(float);
+ method public void setCarrierPhase(double);
+ method public void setCarrierPhaseUncertainty(double);
+ method public void setCn0InDbHz(double);
+ method public void setCodePhaseInChips(double);
+ method public void setCodePhaseUncertaintyInChips(double);
+ method public void setDopplerShiftInHz(double);
+ method public void setDopplerShiftUncertaintyInHz(double);
+ method public void setElevationInDeg(double);
+ method public void setElevationUncertaintyInDeg(double);
+ method public void setLossOfLock(byte);
+ method public void setMultipathIndicator(byte);
+ method public void setPrn(byte);
+ method public void setPseudorangeInMeters(double);
+ method public void setPseudorangeRateCarrierInMetersPerSec(double);
+ method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
+ method public void setPseudorangeRateInMetersPerSec(double);
+ method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+ method public void setPseudorangeUncertaintyInMeters(double);
+ method public void setReceivedGpsTowInNs(long);
+ method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setSnrInDb(double);
+ method public void setState(short);
+ method public void setTimeFromLastBitInMs(short);
+ method public void setTimeOffsetInNs(double);
+ method public void setUsedInFix(boolean);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+ field public static final short ADR_STATE_RESET = 2; // 0x2
+ field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+ field public static final short ADR_STATE_VALID = 1; // 0x1
+ field public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+ field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+ field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+ field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+ field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+ field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+ field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final short STATE_BIT_SYNC = 2; // 0x2
+ field public static final short STATE_CODE_LOCK = 1; // 0x1
+ field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final short STATE_TOW_DECODED = 8; // 0x8
+ field public static final short STATE_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurementsEvent implements android.os.Parcelable {
+ ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+ method public int describeContents();
+ method public android.location.GpsClock getClock();
+ method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+ field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+ field public static final int STATUS_READY = 1; // 0x1
+ }
+
+ public static abstract class GpsMeasurementsEvent.Callback {
+ ctor public GpsMeasurementsEvent.Callback();
+ method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+ method public void onStatusChanged(int);
+ }
+
+ public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessage implements android.os.Parcelable {
+ method public int describeContents();
+ method public byte[] getData();
+ method public short getMessageId();
+ method public byte getPrn();
+ method public short getStatus();
+ method public short getSubmessageId();
+ method public byte getType();
+ method public void reset();
+ method public void set(android.location.GpsNavigationMessage);
+ method public void setData(byte[]);
+ method public void setMessageId(short);
+ method public void setPrn(byte);
+ method public void setStatus(short);
+ method public void setSubmessageId(short);
+ method public void setType(byte);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+ field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+ field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+ field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+ field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+ field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short STATUS_PARITY_PASSED = 1; // 0x1
+ field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+ field public static final short STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+ ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+ method public int describeContents();
+ method public android.location.GpsNavigationMessage getNavigationMessage();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+ field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+ field public static final int STATUS_READY = 1; // 0x1
+ }
+
+ public static abstract class GpsNavigationMessageEvent.Callback {
+ ctor public GpsNavigationMessageEvent.Callback();
+ method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+ method public void onStatusChanged(int);
+ }
+
+ public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+ }
+
public final class GpsSatellite {
method public float getAzimuth();
method public float getElevation();
@@ -19101,8 +19457,10 @@
}
public class LocationManager {
- method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
- method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void clearTestProviderEnabled(java.lang.String);
@@ -19110,14 +19468,21 @@
method public void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
- method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+ method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
method public android.location.Location getLastKnownLocation(java.lang.String);
method public android.location.LocationProvider getProvider(java.lang.String);
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
- method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+ method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public void removeNmeaListener(android.location.GnssNmeaListener);
method public void removeProximityAlert(android.app.PendingIntent);
method public void removeTestProvider(java.lang.String);
method public void removeUpdates(android.location.LocationListener);
@@ -19135,6 +19500,9 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+ method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+ method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
field public static final java.lang.String GPS_PROVIDER = "gps";
field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19201,6 +19569,7 @@
field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+ field public static final int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -19320,6 +19689,7 @@
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
+ field public static final int ENCODING_IEC61937 = 13; // 0xd
field public static final int ENCODING_INVALID = 0; // 0x0
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -19515,6 +19885,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -19564,8 +19935,11 @@
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
- method public int getAudioSessionId();
+ method public android.media.AudioDeviceInfo getAudioDevice();
+ method public int getClientAudioSessionId();
method public int getClientAudioSource();
+ method public android.media.AudioFormat getClientFormat();
+ method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
@@ -19583,6 +19957,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -19597,6 +19973,7 @@
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
+ method public int getBufferCapacityInFrames();
method public int getBufferSizeInFrames();
method public int getChannelConfiguration();
method public int getChannelCount();
@@ -19618,6 +19995,7 @@
method public int getState();
method public int getStreamType();
method public boolean getTimestamp(android.media.AudioTimestamp);
+ method public int getUnderrunCount();
method public void pause() throws java.lang.IllegalStateException;
method public void play() throws java.lang.IllegalStateException;
method public void release();
@@ -19625,6 +20003,7 @@
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
+ method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
method public int setNotificationMarkerPosition(int);
method public int setPlaybackHeadPosition(int);
@@ -19736,6 +20115,16 @@
ctor public DeniedByServerException(java.lang.String);
}
+ public abstract class DrmInitData {
+ ctor public DrmInitData();
+ method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+ }
+
+ public static final class DrmInitData.SchemeInitData {
+ field public final byte[] data;
+ field public final java.lang.String mimeType;
+ }
+
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
method public double getAltitude(double);
@@ -20225,6 +20614,24 @@
field public static final int VP8Level_Version2 = 4; // 0x4
field public static final int VP8Level_Version3 = 8; // 0x8
field public static final int VP8ProfileMain = 1; // 0x1
+ field public static final int VP9Level1 = 0; // 0x0
+ field public static final int VP9Level11 = 1; // 0x1
+ field public static final int VP9Level2 = 2; // 0x2
+ field public static final int VP9Level21 = 4; // 0x4
+ field public static final int VP9Level3 = 8; // 0x8
+ field public static final int VP9Level31 = 16; // 0x10
+ field public static final int VP9Level4 = 32; // 0x20
+ field public static final int VP9Level41 = 64; // 0x40
+ field public static final int VP9Level5 = 128; // 0x80
+ field public static final int VP9Level51 = 256; // 0x100
+ field public static final int VP9Level52 = 512; // 0x200
+ field public static final int VP9Level6 = 1024; // 0x400
+ field public static final int VP9Level61 = 2048; // 0x800
+ field public static final int VP9Level62 = 4096; // 0x1000
+ field public static final int VP9Profile0 = 0; // 0x0
+ field public static final int VP9Profile1 = 1; // 0x1
+ field public static final int VP9Profile2 = 2; // 0x2
+ field public static final int VP9Profile3 = 3; // 0x3
field public int level;
field public int profile;
}
@@ -20408,6 +20815,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.DrmInitData getDrmInitData();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
method public int getSampleFlags();
@@ -20452,6 +20860,16 @@
method public final void setInteger(java.lang.String, int);
method public final void setLong(java.lang.String, long);
method public final void setString(java.lang.String, java.lang.String);
+ field public static final int COLOR_RANGE_FULL = 1; // 0x1
+ field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+ field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+ field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+ field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+ field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+ field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+ field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -20467,6 +20885,9 @@
field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+ field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+ field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+ field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
field public static final java.lang.String KEY_COMPLEXITY = "complexity";
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
@@ -22092,6 +22513,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22170,6 +22592,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22486,7 +22909,8 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onInputUpdated(java.lang.String);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22494,7 +22918,7 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -22565,7 +22989,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -22757,6 +23181,7 @@
field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+ field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -22794,6 +23219,7 @@
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+ method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22802,7 +23228,7 @@
method public boolean importFile(int, android.os.ParcelFileDescriptor);
method public boolean open(android.hardware.usb.UsbDeviceConnection);
method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
- method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+ method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
}
@@ -22833,23 +23259,31 @@
method public final int getAssociationDesc();
method public final int getAssociationType();
method public final int getCompressedSize();
+ method public final long getCompressedSizeLong();
method public final long getDateCreated();
method public final long getDateModified();
method public final int getFormat();
method public final int getImagePixDepth();
+ method public final long getImagePixDepthLong();
method public final int getImagePixHeight();
+ method public final long getImagePixHeightLong();
method public final int getImagePixWidth();
+ method public final long getImagePixWidthLong();
method public final java.lang.String getKeywords();
method public final java.lang.String getName();
method public final int getObjectHandle();
method public final int getParent();
method public final int getProtectionStatus();
method public final int getSequenceNumber();
+ method public final long getSequenceNumberLong();
method public final int getStorageId();
method public final int getThumbCompressedSize();
+ method public final long getThumbCompressedSizeLong();
method public final int getThumbFormat();
method public final int getThumbPixHeight();
+ method public final long getThumbPixHeightLong();
method public final int getThumbPixWidth();
+ method public final long getThumbPixWidthLong();
}
public static class MtpObjectInfo.Builder {
@@ -22858,24 +23292,24 @@
method public android.mtp.MtpObjectInfo build();
method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
- method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
method public android.mtp.MtpObjectInfo.Builder setFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
- method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+ method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
}
public final class MtpStorageInfo {
@@ -28122,6 +28556,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -28553,6 +28991,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -28712,6 +29151,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -28818,6 +29258,8 @@
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+ field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+ field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
}
public abstract class Vibrator {
@@ -29175,6 +29617,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -31169,7 +31613,9 @@
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+ method public static boolean isTreeUri(android.net.Uri);
method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -31195,6 +31641,7 @@
field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+ field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -31242,6 +31689,7 @@
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+ method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -31621,6 +32069,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -32282,6 +32731,7 @@
public class VoicemailContract {
field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+ field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -32296,8 +32746,13 @@
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+ field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+ field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+ field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+ field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+ field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -32395,6 +32850,7 @@
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
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);
@@ -32410,9 +32866,12 @@
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
method public void generateMipmaps();
+ method public java.nio.ByteBuffer getByteBuffer();
method public int getBytesSize();
method public android.renderscript.Element getElement();
+ method public long getStride();
method public android.view.Surface getSurface();
+ method public long getTimeStamp();
method public android.renderscript.Type getType();
method public int getUsage();
method public void ioReceive();
@@ -35353,6 +35812,30 @@
field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
}
+ public abstract class CallScreeningService extends android.app.Service {
+ ctor public CallScreeningService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onScreenCall(android.telecom.Call.Details);
+ method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+ }
+
+ public static class CallScreeningService.CallResponse {
+ method public boolean getDisallowCall();
+ method public boolean getRejectCall();
+ method public boolean getSkipCallLog();
+ method public boolean getSkipNotification();
+ }
+
+ public static class CallScreeningService.CallResponse.Builder {
+ ctor public CallScreeningService.CallResponse.Builder();
+ method public android.telecom.CallScreeningService.CallResponse build();
+ method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+ }
+
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
@@ -35592,6 +36075,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Call);
method public void onCanAddCallChanged(boolean);
+ method public void onSilenceRinger();
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -35852,6 +36336,7 @@
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -36003,6 +36488,7 @@
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+ field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -36728,7 +37214,7 @@
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
method public T getActivity();
@@ -36736,14 +37222,14 @@
method public void setActivityIntent(android.content.Intent);
}
- public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
ctor public ActivityTestCase();
method protected android.app.Activity getActivity();
method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
method protected void setActivity(android.app.Activity);
}
- public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
ctor public ActivityUnitTestCase(java.lang.Class<T>);
method public T getActivity();
method public int getFinishedActivityRequest();
@@ -36756,7 +37242,7 @@
method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
}
- public class AndroidTestCase extends junit.framework.TestCase {
+ public deprecated class AndroidTestCase extends junit.framework.TestCase {
ctor public AndroidTestCase();
method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -36768,7 +37254,7 @@
field protected android.content.Context mContext;
}
- public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+ public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
ctor public AndroidTestRunner();
method public void addTestListener(junit.framework.TestListener);
method public void clearTestListeners();
@@ -36789,7 +37275,7 @@
method public void testStarted(java.lang.String);
}
- public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
ctor public ApplicationTestCase(java.lang.Class<T>);
method protected final void createApplication();
method public T getApplication();
@@ -36807,10 +37293,10 @@
ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
}
- public abstract class FlakyTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
}
- public class InstrumentationTestCase extends junit.framework.TestCase {
+ public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
ctor public InstrumentationTestCase();
method public android.app.Instrumentation getInstrumentation();
method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36823,7 +37309,7 @@
method public void sendRepeatedKeys(int...);
}
- public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+ public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
ctor public InstrumentationTestRunner();
method public junit.framework.TestSuite getAllTests();
method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36842,14 +37328,14 @@
field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
}
- public class InstrumentationTestSuite extends junit.framework.TestSuite {
+ public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
ctor public InstrumentationTestSuite(android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
method public void addTestSuite(java.lang.Class);
}
- public class IsolatedContext extends android.content.ContextWrapper {
+ public deprecated class IsolatedContext extends android.content.ContextWrapper {
ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
}
@@ -36859,7 +37345,7 @@
method public T getLoaderResultSynchronously(android.content.Loader<T>);
}
- public final class MoreAsserts {
+ public final deprecated class MoreAsserts {
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -36898,7 +37384,7 @@
method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
}
- public abstract interface PerformanceTestCase {
+ public abstract deprecated interface PerformanceTestCase {
method public abstract boolean isPerformanceOnly();
method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
}
@@ -36927,7 +37413,7 @@
method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public class RenamingDelegatingContext extends android.content.ContextWrapper {
+ public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
method public java.lang.String getDatabasePrefix();
@@ -36936,7 +37422,7 @@
method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
ctor public ServiceTestCase(java.lang.Class<T>);
method protected android.os.IBinder bindService(android.content.Intent);
method public android.app.Application getApplication();
@@ -36949,23 +37435,23 @@
method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
method public T getActivity();
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+ public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
ctor public SyncBaseInstrumentation();
method protected void cancelSyncsandDisableAutoSync();
method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
}
- public abstract interface TestSuiteProvider {
+ public abstract deprecated interface TestSuiteProvider {
method public abstract junit.framework.TestSuite getTestSuite();
}
- public class TouchUtils {
+ public deprecated class TouchUtils {
ctor public TouchUtils();
method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -37000,10 +37486,10 @@
method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
}
- public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
}
- public class ViewAsserts {
+ public deprecated class ViewAsserts {
method public static void assertBaselineAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -37028,11 +37514,11 @@
package android.test.mock {
- public class MockApplication extends android.app.Application {
+ public deprecated class MockApplication extends android.app.Application {
ctor public MockApplication();
}
- public class MockContentProvider extends android.content.ContentProvider {
+ public deprecated class MockContentProvider extends android.content.ContentProvider {
ctor protected MockContentProvider();
ctor public MockContentProvider(android.content.Context);
ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -37044,13 +37530,13 @@
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
}
- public class MockContentResolver extends android.content.ContentResolver {
+ public deprecated class MockContentResolver extends android.content.ContentResolver {
ctor public MockContentResolver();
ctor public MockContentResolver(android.content.Context);
method public void addProvider(java.lang.String, android.content.ContentProvider);
}
- public class MockContext extends android.content.Context {
+ public deprecated class MockContext extends android.content.Context {
ctor public MockContext();
method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
method public int checkCallingOrSelfPermission(java.lang.String);
@@ -37150,7 +37636,7 @@
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class MockCursor implements android.database.Cursor {
+ public deprecated class MockCursor implements android.database.Cursor {
ctor public MockCursor();
method public void close();
method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -37195,13 +37681,13 @@
method public void unregisterDataSetObserver(android.database.DataSetObserver);
}
- public class MockDialogInterface implements android.content.DialogInterface {
+ public deprecated class MockDialogInterface implements android.content.DialogInterface {
ctor public MockDialogInterface();
method public void cancel();
method public void dismiss();
}
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
method public void addPackageToPreferred(java.lang.String);
method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -37288,7 +37774,7 @@
method public void verifyPendingInstall(int, int);
}
- public class MockResources extends android.content.res.Resources {
+ public deprecated class MockResources extends android.content.res.Resources {
ctor public MockResources();
}
@@ -37329,19 +37815,19 @@
package android.test.suitebuilder.annotation {
- public abstract class LargeTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
}
- public abstract class MediumTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
}
- public abstract class SmallTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
}
- public abstract class Smoke implements java.lang.annotation.Annotation {
+ public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
}
- public abstract class Suppress implements java.lang.annotation.Annotation {
+ public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
}
}
@@ -39395,6 +39881,7 @@
field public static final int DENSITY_420 = 420; // 0x1a4
field public static final int DENSITY_560 = 560; // 0x230
field public static final int DENSITY_DEFAULT = 160; // 0xa0
+ field public static final int DENSITY_DEVICE_STABLE;
field public static final int DENSITY_HIGH = 240; // 0xf0
field public static final int DENSITY_LOW = 120; // 0x78
field public static final int DENSITY_MEDIUM = 160; // 0xa0
@@ -50840,6 +51327,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/removed.txt b/api/removed.txt
index 6b7961e..2c6729d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -201,7 +201,7 @@
package android.test.mock {
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public deprecated java.lang.String getDefaultBrowserPackageName(int);
method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8e247ad..2ab45cb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -46,6 +46,7 @@
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
@@ -600,6 +601,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -975,6 +978,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1226,6 +1230,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -2721,6 +2727,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2779,6 +2786,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4768,6 +4787,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5664,6 +5684,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5680,6 +5701,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5955,6 +5977,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -6030,6 +6053,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6552,7 +6576,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6561,9 +6584,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -6768,8 +6788,9 @@
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
- field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
}
@@ -7607,6 +7628,8 @@
method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
method public void startScan(android.bluetooth.le.ScanCallback);
method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
+ method public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
method public void stopScan(android.bluetooth.le.ScanCallback);
}
@@ -9947,6 +9970,7 @@
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
@@ -10346,7 +10370,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10355,13 +10379,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10465,6 +10494,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10524,6 +10558,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10559,6 +10594,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
@@ -13755,6 +13791,7 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
+ method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isDataInjectionSupported();
@@ -13765,16 +13802,19 @@
field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+ field public static final java.lang.String STRING_TYPE_DYNAMIC_SENSOR_META = "android.sensor.dynamic_sensor_meta";
field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
@@ -13782,6 +13822,7 @@
field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+ field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13789,16 +13830,19 @@
field public static final int TYPE_ACCELEROMETER = 1; // 0x1
field public static final int TYPE_ALL = -1; // 0xffffffff
field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
+ field public static final int TYPE_DYNAMIC_SENSOR_META = 32; // 0x20
field public static final int TYPE_GAME_ROTATION_VECTOR = 15; // 0xf
field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEART_BEAT = 31; // 0x1f
field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_LIGHT = 5; // 0x5
field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+ field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
field public static final int TYPE_POSE_6DOF = 28; // 0x1c
field public static final int TYPE_PRESSURE = 6; // 0x6
@@ -13806,12 +13850,28 @@
field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+ field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
field public static final int TYPE_STEP_COUNTER = 19; // 0x13
field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
}
+ public class SensorAdditionalInfo {
+ field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+ field public static final int TYPE_FRAME_END = 1; // 0x1
+ field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+ field public static final int TYPE_SAMPLING = 65540; // 0x10004
+ field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+ field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+ field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+ field public final float[] floatValues;
+ field public final int[] intValues;
+ field public final android.hardware.Sensor sensor;
+ field public final int serial;
+ field public final int type;
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -13819,6 +13879,14 @@
field public final float[] values;
}
+ public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+ ctor public SensorEventCallback();
+ method public void onAccuracyChanged(android.hardware.Sensor, int);
+ method public void onFlushCompleted(android.hardware.Sensor);
+ method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+ method public void onSensorChanged(android.hardware.SensorEvent);
+ }
+
public abstract interface SensorEventListener {
method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13840,6 +13908,7 @@
method public static void getAngleChange(float[], float[], float[]);
method public android.hardware.Sensor getDefaultSensor(int);
method public android.hardware.Sensor getDefaultSensor(int, boolean);
+ method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
method public static float getInclination(float[]);
method public static float[] getOrientation(float[], float[]);
method public static void getQuaternionFromVector(float[], float[]);
@@ -13849,6 +13918,8 @@
method public deprecated int getSensors();
method public boolean initDataInjection(boolean);
method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13857,6 +13928,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13921,6 +13993,12 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
+ public static abstract class SensorManager.DynamicSensorConnectionCallback {
+ ctor public SensorManager.DynamicSensorConnectionCallback();
+ method public void onDynamicSensorConnected(android.hardware.Sensor);
+ method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+ }
+
public final class TriggerEvent {
field public android.hardware.Sensor sensor;
field public long timestamp;
@@ -15060,6 +15138,66 @@
package android.hardware.location {
+ public class ContextHubInfo {
+ ctor public ContextHubInfo();
+ method public int describeContents();
+ method public int getId();
+ method public android.hardware.location.MemoryRegion[] getMemoryRegions();
+ method public java.lang.String getName();
+ method public float getPeakMips();
+ method public float getPeakPowerDrawMw();
+ method public int getPlatformVersion();
+ method public float getSleepPowerDrawMw();
+ method public int getStaticSwVersion();
+ method public float getStoppedPowerDrawMw();
+ method public int[] getSupportedSensors();
+ method public java.lang.String getToolchain();
+ method public int getToolchainVersion();
+ method public java.lang.String getVendor();
+ method public void setId(int);
+ method public void setMemoryRegions(android.hardware.location.MemoryRegion[]);
+ method public void setName(java.lang.String);
+ method public void setPeakMips(float);
+ method public void setPeakPowerDrawMw(float);
+ method public void setPlatformVersion(int);
+ method public void setSleepPowerDrawMw(float);
+ method public void setStaticSwVersion(int);
+ method public void setStoppedPowerDrawMw(float);
+ method public void setSupportedSensors(int[]);
+ method public void setToolchain(java.lang.String);
+ method public void setToolchainVersion(int);
+ method public void setVendor(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
+ }
+
+ public final class ContextHubManager {
+ method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+ method public int[] getContexthubHandles();
+ method public android.hardware.location.ContextHubInfo getContexthubInfo(int);
+ method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+ method public int loadNanoApp(int, android.hardware.location.NanoApp);
+ method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
+ method public int unloadNanoApp(int);
+ field public static final int ANY_HUB = -1; // 0xffffffff
+ field public static final int MSG_DATA_SEND = 3; // 0x3
+ field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
+ field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
+ }
+
+ public class ContextHubMessage {
+ ctor public ContextHubMessage(int, int, byte[]);
+ method public int describeContents();
+ method public byte[] getData();
+ method public int getMsgType();
+ method public int getVersion();
+ method public void setMsgData(byte[]);
+ method public void setMsgType(int);
+ method public void setVersion(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+ }
+
public final class GeofenceHardware {
ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
@@ -15176,6 +15314,89 @@
method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
}
+ public class MemoryRegion implements android.os.Parcelable {
+ ctor public MemoryRegion(android.os.Parcel);
+ method public int describeContents();
+ method public int getCapacityBytes();
+ method public int getFreeCapacityBytes();
+ method public boolean isExecutable();
+ method public boolean isReadable();
+ method public boolean isWritable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
+ }
+
+ public class NanoApp {
+ ctor public NanoApp();
+ method public int describeContents();
+ method public byte[] getAppBinary();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppBinary(byte[]);
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
+ }
+
+ public class NanoAppFilter {
+ ctor public NanoAppFilter(long, int, int, long);
+ method public int describeContents();
+ method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int APP_ANY = -1; // 0xffffffff
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+ field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+ field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+ field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+ field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+ field public static final int HUB_ANY = -1; // 0xffffffff
+ field public static final int VENDOR_ANY = -1; // 0xffffffff
+ }
+
+ public class NanoAppInstanceInfo {
+ ctor public NanoAppInstanceInfo();
+ method public int describeContents();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public int getContexthubId();
+ method public int getHandle();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setContexthubId(int);
+ method public void setHandle(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
+ }
+
}
package android.hardware.radio {
@@ -20050,7 +20271,38 @@
method public static boolean isPresent();
}
- public class GpsClock implements android.os.Parcelable {
+ public abstract interface GnssNmeaListener {
+ method public abstract void onNmeaReceived(long, java.lang.String);
+ }
+
+ public final class GnssStatus {
+ method public float getAzimuth(int);
+ method public int getConstellationType(int);
+ method public float getElevation(int);
+ method public int getNumSatellites();
+ method public int getPrn(int);
+ method public float getSnr(int);
+ method public boolean hasAlmanac(int);
+ method public boolean hasEphemeris(int);
+ method public boolean usedInFix(int);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract class GnssStatusCallback {
+ ctor public GnssStatusCallback();
+ method public void onFirstFix(int);
+ method public void onSatelliteStatusChanged(android.location.GnssStatus);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class GpsClock implements android.os.Parcelable {
method public int describeContents();
method public double getBiasInNs();
method public double getBiasUncertaintyInNs();
@@ -20059,6 +20311,7 @@
method public long getFullBiasInNs();
method public short getLeapSecond();
method public long getTimeInNs();
+ method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
method public byte getType();
method public boolean hasBiasInNs();
@@ -20084,16 +20337,20 @@
method public void setFullBiasInNs(long);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
+ method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+ field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+ field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
- field public static final byte TYPE_GPS_TIME = 2; // 0x2
- field public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte TYPE_UNKNOWN = 0; // 0x0
}
- public class GpsMeasurement implements android.os.Parcelable {
+ public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
method public short getAccumulatedDeltaRangeState();
@@ -20116,6 +20373,8 @@
method public byte getMultipathIndicator();
method public byte getPrn();
method public double getPseudorangeInMeters();
+ method public double getPseudorangeRateCarrierInMetersPerSec();
+ method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
@@ -20184,6 +20443,8 @@
method public void setMultipathIndicator(byte);
method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
+ method public void setPseudorangeRateCarrierInMetersPerSec(double);
+ method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
@@ -20214,7 +20475,13 @@
field public static final short STATE_UNKNOWN = 0; // 0x0
}
- public class GpsMeasurementsEvent implements android.os.Parcelable {
+ public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurementsEvent implements android.os.Parcelable {
ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
method public int describeContents();
method public android.location.GpsClock getClock();
@@ -20226,12 +20493,16 @@
field public static final int STATUS_READY = 1; // 0x1
}
- public static abstract interface GpsMeasurementsEvent.Listener {
- method public abstract void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
- method public abstract void onStatusChanged(int);
+ public static abstract class GpsMeasurementsEvent.Callback {
+ ctor public GpsMeasurementsEvent.Callback();
+ method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+ method public void onStatusChanged(int);
}
- public class GpsNavigationMessage implements android.os.Parcelable {
+ public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessage implements android.os.Parcelable {
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
@@ -20249,30 +20520,37 @@
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+ field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+ field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+ field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+ field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+ field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
- field public static final byte TYPE_CNAV2 = 4; // 0x4
- field public static final byte TYPE_L1CA = 1; // 0x1
- field public static final byte TYPE_L2CNAV = 2; // 0x2
- field public static final byte TYPE_L5CNAV = 3; // 0x3
- field public static final byte TYPE_UNKNOWN = 0; // 0x0
}
- public class GpsNavigationMessageEvent implements android.os.Parcelable {
+ public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessageEvent implements android.os.Parcelable {
ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
method public int describeContents();
method public android.location.GpsNavigationMessage getNavigationMessage();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
- field public static int STATUS_GPS_LOCATION_DISABLED;
- field public static int STATUS_NOT_SUPPORTED;
- field public static int STATUS_READY;
+ field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+ field public static final int STATUS_READY = 1; // 0x1
}
- public static abstract interface GpsNavigationMessageEvent.Listener {
- method public abstract void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
- method public abstract void onStatusChanged(int);
+ public static abstract class GpsNavigationMessageEvent.Callback {
+ ctor public GpsNavigationMessageEvent.Callback();
+ method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+ method public void onStatusChanged(int);
+ }
+
+ public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
}
public final class GpsSatellite {
@@ -20379,10 +20657,10 @@
}
public class LocationManager {
- method public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
- method public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
- method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
- method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void clearTestProviderEnabled(java.lang.String);
@@ -20390,16 +20668,21 @@
method public void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
- method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+ method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
method public android.location.Location getLastKnownLocation(java.lang.String);
method public android.location.LocationProvider getProvider(java.lang.String);
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
- method public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
- method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
- method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+ method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public void removeNmeaListener(android.location.GnssNmeaListener);
method public void removeProximityAlert(android.app.PendingIntent);
method public void removeTestProvider(java.lang.String);
method public void removeUpdates(android.location.LocationListener);
@@ -20419,6 +20702,9 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+ method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+ method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
field public static final java.lang.String GPS_PROVIDER = "gps";
field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -20525,6 +20811,7 @@
field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
field public static final int FLAG_HW_HOTWORD = 32; // 0x20
+ field public static final int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20658,6 +20945,7 @@
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
+ field public static final int ENCODING_IEC61937 = 13; // 0xd
field public static final int ENCODING_INVALID = 0; // 0x0
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -20863,6 +21151,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -20914,8 +21203,11 @@
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
- method public int getAudioSessionId();
+ method public android.media.AudioDeviceInfo getAudioDevice();
+ method public int getClientAudioSessionId();
method public int getClientAudioSource();
+ method public android.media.AudioFormat getClientFormat();
+ method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
@@ -20933,6 +21225,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -20947,6 +21241,7 @@
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
+ method public int getBufferCapacityInFrames();
method public int getBufferSizeInFrames();
method public int getChannelConfiguration();
method public int getChannelCount();
@@ -20968,6 +21263,7 @@
method public int getState();
method public int getStreamType();
method public boolean getTimestamp(android.media.AudioTimestamp);
+ method public int getUnderrunCount();
method public void pause() throws java.lang.IllegalStateException;
method public void play() throws java.lang.IllegalStateException;
method public void release();
@@ -20975,6 +21271,7 @@
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
+ method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
method public int setNotificationMarkerPosition(int);
method public int setPlaybackHeadPosition(int);
@@ -21086,6 +21383,16 @@
ctor public DeniedByServerException(java.lang.String);
}
+ public abstract class DrmInitData {
+ ctor public DrmInitData();
+ method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+ }
+
+ public static final class DrmInitData.SchemeInitData {
+ field public final byte[] data;
+ field public final java.lang.String mimeType;
+ }
+
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
method public double getAltitude(double);
@@ -21575,6 +21882,24 @@
field public static final int VP8Level_Version2 = 4; // 0x4
field public static final int VP8Level_Version3 = 8; // 0x8
field public static final int VP8ProfileMain = 1; // 0x1
+ field public static final int VP9Level1 = 0; // 0x0
+ field public static final int VP9Level11 = 1; // 0x1
+ field public static final int VP9Level2 = 2; // 0x2
+ field public static final int VP9Level21 = 4; // 0x4
+ field public static final int VP9Level3 = 8; // 0x8
+ field public static final int VP9Level31 = 16; // 0x10
+ field public static final int VP9Level4 = 32; // 0x20
+ field public static final int VP9Level41 = 64; // 0x40
+ field public static final int VP9Level5 = 128; // 0x80
+ field public static final int VP9Level51 = 256; // 0x100
+ field public static final int VP9Level52 = 512; // 0x200
+ field public static final int VP9Level6 = 1024; // 0x400
+ field public static final int VP9Level61 = 2048; // 0x800
+ field public static final int VP9Level62 = 4096; // 0x1000
+ field public static final int VP9Profile0 = 0; // 0x0
+ field public static final int VP9Profile1 = 1; // 0x1
+ field public static final int VP9Profile2 = 2; // 0x2
+ field public static final int VP9Profile3 = 3; // 0x3
field public int level;
field public int profile;
}
@@ -21758,6 +22083,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.DrmInitData getDrmInitData();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
method public int getSampleFlags();
@@ -21802,6 +22128,16 @@
method public final void setInteger(java.lang.String, int);
method public final void setLong(java.lang.String, long);
method public final void setString(java.lang.String, java.lang.String);
+ field public static final int COLOR_RANGE_FULL = 1; // 0x1
+ field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+ field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+ field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+ field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+ field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+ field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+ field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -21817,6 +22153,9 @@
field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+ field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+ field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+ field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
field public static final java.lang.String KEY_COMPLEXITY = "complexity";
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
@@ -23127,12 +23466,15 @@
public class AudioMixingRule {
field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
+ field public static final int RULE_MATCH_UID = 4; // 0x4
}
public static class AudioMixingRule.Builder {
ctor public AudioMixingRule.Builder();
+ method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMixingRule build();
+ method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
}
@@ -23512,6 +23854,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -23590,6 +23933,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -23638,6 +23982,38 @@
}
+package android.media.soundtrigger {
+
+ public final class SoundTriggerDetector {
+ method public boolean startRecognition();
+ method public boolean stopRecognition();
+ }
+
+ public abstract class SoundTriggerDetector.Callback {
+ ctor public SoundTriggerDetector.Callback();
+ method public abstract void onAvailabilityChanged(int);
+ method public abstract void onDetected();
+ method public abstract void onError();
+ method public abstract void onRecognitionPaused();
+ method public abstract void onRecognitionResumed();
+ }
+
+ public final class SoundTriggerManager {
+ method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler);
+ method public void deleteModel(java.util.UUID);
+ method public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+ method public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
+ }
+
+ public static class SoundTriggerManager.Model {
+ method public static android.media.soundtrigger.SoundTriggerManager.Model create(java.util.UUID, java.util.UUID, byte[]);
+ method public byte[] getModelData();
+ method public java.util.UUID getModelUuid();
+ method public java.util.UUID getVendorUuid();
+ }
+
+}
+
package android.media.tv {
public final class TvContentRating {
@@ -24048,7 +24424,7 @@
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
method public void onInputUpdated(java.lang.String);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -24060,7 +24436,7 @@
method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -24140,7 +24516,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -24367,6 +24743,7 @@
field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+ field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -24404,6 +24781,7 @@
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+ method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -24412,7 +24790,7 @@
method public boolean importFile(int, android.os.ParcelFileDescriptor);
method public boolean open(android.hardware.usb.UsbDeviceConnection);
method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
- method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+ method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
}
@@ -24443,23 +24821,31 @@
method public final int getAssociationDesc();
method public final int getAssociationType();
method public final int getCompressedSize();
+ method public final long getCompressedSizeLong();
method public final long getDateCreated();
method public final long getDateModified();
method public final int getFormat();
method public final int getImagePixDepth();
+ method public final long getImagePixDepthLong();
method public final int getImagePixHeight();
+ method public final long getImagePixHeightLong();
method public final int getImagePixWidth();
+ method public final long getImagePixWidthLong();
method public final java.lang.String getKeywords();
method public final java.lang.String getName();
method public final int getObjectHandle();
method public final int getParent();
method public final int getProtectionStatus();
method public final int getSequenceNumber();
+ method public final long getSequenceNumberLong();
method public final int getStorageId();
method public final int getThumbCompressedSize();
+ method public final long getThumbCompressedSizeLong();
method public final int getThumbFormat();
method public final int getThumbPixHeight();
+ method public final long getThumbPixHeightLong();
method public final int getThumbPixWidth();
+ method public final long getThumbPixWidthLong();
}
public static class MtpObjectInfo.Builder {
@@ -24468,24 +24854,24 @@
method public android.mtp.MtpObjectInfo build();
method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
- method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
method public android.mtp.MtpObjectInfo.Builder setFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
- method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+ method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
}
public final class MtpStorageInfo {
@@ -30197,6 +30583,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -30631,6 +31021,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
@@ -30795,6 +31186,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -30838,6 +31230,7 @@
method public deprecated boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
+ method public static android.os.UserHandle of(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -30852,6 +31245,7 @@
method public android.os.PersistableBundle getSeedAccountOptions();
method public java.lang.String getSeedAccountType();
method public long getSerialNumberForUser(android.os.UserHandle);
+ method public long[] getSerialNumbersOfUsers(boolean);
method public int getUserCount();
method public long getUserCreationTime(android.os.UserHandle);
method public android.os.UserHandle getUserForSerialNumber(long);
@@ -30910,6 +31304,8 @@
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+ field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+ field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
}
public abstract class Vibrator {
@@ -31267,6 +31663,9 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageCredentialEncrypted();
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -33291,7 +33690,9 @@
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+ method public static boolean isTreeUri(android.net.Uri);
method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -33317,6 +33718,7 @@
field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+ field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -33364,6 +33766,7 @@
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+ method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -33845,6 +34248,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -34507,6 +34911,7 @@
public class VoicemailContract {
field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+ field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -34521,8 +34926,13 @@
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+ field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+ field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+ field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+ field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+ field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -34620,6 +35030,7 @@
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
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);
@@ -34635,9 +35046,12 @@
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
method public void generateMipmaps();
+ method public java.nio.ByteBuffer getByteBuffer();
method public int getBytesSize();
method public android.renderscript.Element getElement();
+ method public long getStride();
method public android.view.Surface getSurface();
+ method public long getTimeStamp();
method public android.renderscript.Type getType();
method public int getUsage();
method public void ioReceive();
@@ -37658,6 +38072,30 @@
field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
}
+ public abstract class CallScreeningService extends android.app.Service {
+ ctor public CallScreeningService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onScreenCall(android.telecom.Call.Details);
+ method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+ }
+
+ public static class CallScreeningService.CallResponse {
+ method public boolean getDisallowCall();
+ method public boolean getRejectCall();
+ method public boolean getSkipCallLog();
+ method public boolean getSkipNotification();
+ }
+
+ public static class CallScreeningService.CallResponse.Builder {
+ ctor public CallScreeningService.CallResponse.Builder();
+ method public android.telecom.CallScreeningService.CallResponse build();
+ method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+ }
+
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
@@ -37907,6 +38345,7 @@
method public void onCanAddCallChanged(boolean);
method public deprecated void onPhoneCreated(android.telecom.Phone);
method public deprecated void onPhoneDestroyed(android.telecom.Phone);
+ method public void onSilenceRinger();
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -37988,6 +38427,7 @@
method public void onCallAudioStateChanged(android.telecom.Phone, android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Phone, android.telecom.Call);
method public void onCanAddCallChanged(android.telecom.Phone, boolean);
+ method public void onSilenceRinger(android.telecom.Phone);
}
public final class PhoneAccount implements android.os.Parcelable {
@@ -38247,6 +38687,7 @@
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -38400,6 +38841,7 @@
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+ field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -39178,7 +39620,7 @@
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
method public T getActivity();
@@ -39186,14 +39628,14 @@
method public void setActivityIntent(android.content.Intent);
}
- public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
ctor public ActivityTestCase();
method protected android.app.Activity getActivity();
method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
method protected void setActivity(android.app.Activity);
}
- public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
ctor public ActivityUnitTestCase(java.lang.Class<T>);
method public T getActivity();
method public int getFinishedActivityRequest();
@@ -39206,7 +39648,7 @@
method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
}
- public class AndroidTestCase extends junit.framework.TestCase {
+ public deprecated class AndroidTestCase extends junit.framework.TestCase {
ctor public AndroidTestCase();
method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -39218,7 +39660,7 @@
field protected android.content.Context mContext;
}
- public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+ public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
ctor public AndroidTestRunner();
method public void addTestListener(junit.framework.TestListener);
method public void clearTestListeners();
@@ -39239,7 +39681,7 @@
method public void testStarted(java.lang.String);
}
- public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
ctor public ApplicationTestCase(java.lang.Class<T>);
method protected final void createApplication();
method public T getApplication();
@@ -39257,10 +39699,10 @@
ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
}
- public abstract class FlakyTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
}
- public class InstrumentationTestCase extends junit.framework.TestCase {
+ public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
ctor public InstrumentationTestCase();
method public android.app.Instrumentation getInstrumentation();
method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -39273,7 +39715,7 @@
method public void sendRepeatedKeys(int...);
}
- public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+ public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
ctor public InstrumentationTestRunner();
method public junit.framework.TestSuite getAllTests();
method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -39292,14 +39734,14 @@
field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
}
- public class InstrumentationTestSuite extends junit.framework.TestSuite {
+ public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
ctor public InstrumentationTestSuite(android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
method public void addTestSuite(java.lang.Class);
}
- public class IsolatedContext extends android.content.ContextWrapper {
+ public deprecated class IsolatedContext extends android.content.ContextWrapper {
ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
}
@@ -39309,7 +39751,7 @@
method public T getLoaderResultSynchronously(android.content.Loader<T>);
}
- public final class MoreAsserts {
+ public final deprecated class MoreAsserts {
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -39348,7 +39790,7 @@
method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
}
- public abstract interface PerformanceTestCase {
+ public abstract deprecated interface PerformanceTestCase {
method public abstract boolean isPerformanceOnly();
method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
}
@@ -39377,7 +39819,7 @@
method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public class RenamingDelegatingContext extends android.content.ContextWrapper {
+ public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
method public java.lang.String getDatabasePrefix();
@@ -39386,7 +39828,7 @@
method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
ctor public ServiceTestCase(java.lang.Class<T>);
method protected android.os.IBinder bindService(android.content.Intent);
method public android.app.Application getApplication();
@@ -39399,23 +39841,23 @@
method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
method public T getActivity();
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+ public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
ctor public SyncBaseInstrumentation();
method protected void cancelSyncsandDisableAutoSync();
method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
}
- public abstract interface TestSuiteProvider {
+ public abstract deprecated interface TestSuiteProvider {
method public abstract junit.framework.TestSuite getTestSuite();
}
- public class TouchUtils {
+ public deprecated class TouchUtils {
ctor public TouchUtils();
method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -39450,10 +39892,10 @@
method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
}
- public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
}
- public class ViewAsserts {
+ public deprecated class ViewAsserts {
method public static void assertBaselineAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -39478,11 +39920,11 @@
package android.test.mock {
- public class MockApplication extends android.app.Application {
+ public deprecated class MockApplication extends android.app.Application {
ctor public MockApplication();
}
- public class MockContentProvider extends android.content.ContentProvider {
+ public deprecated class MockContentProvider extends android.content.ContentProvider {
ctor protected MockContentProvider();
ctor public MockContentProvider(android.content.Context);
ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -39494,13 +39936,13 @@
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
}
- public class MockContentResolver extends android.content.ContentResolver {
+ public deprecated class MockContentResolver extends android.content.ContentResolver {
ctor public MockContentResolver();
ctor public MockContentResolver(android.content.Context);
method public void addProvider(java.lang.String, android.content.ContentProvider);
}
- public class MockContext extends android.content.Context {
+ public deprecated class MockContext extends android.content.Context {
ctor public MockContext();
method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
method public int checkCallingOrSelfPermission(java.lang.String);
@@ -39604,7 +40046,7 @@
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class MockCursor implements android.database.Cursor {
+ public deprecated class MockCursor implements android.database.Cursor {
ctor public MockCursor();
method public void close();
method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -39649,13 +40091,13 @@
method public void unregisterDataSetObserver(android.database.DataSetObserver);
}
- public class MockDialogInterface implements android.content.DialogInterface {
+ public deprecated class MockDialogInterface implements android.content.DialogInterface {
ctor public MockDialogInterface();
method public void cancel();
method public void dismiss();
}
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void addPackageToPreferred(java.lang.String);
@@ -39749,7 +40191,7 @@
method public void verifyPendingInstall(int, int);
}
- public class MockResources extends android.content.res.Resources {
+ public deprecated class MockResources extends android.content.res.Resources {
ctor public MockResources();
}
@@ -39790,19 +40232,19 @@
package android.test.suitebuilder.annotation {
- public abstract class LargeTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
}
- public abstract class MediumTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
}
- public abstract class SmallTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
}
- public abstract class Smoke implements java.lang.annotation.Annotation {
+ public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
}
- public abstract class Suppress implements java.lang.annotation.Annotation {
+ public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
}
}
@@ -41856,6 +42298,7 @@
field public static final int DENSITY_420 = 420; // 0x1a4
field public static final int DENSITY_560 = 560; // 0x230
field public static final int DENSITY_DEFAULT = 160; // 0xa0
+ field public static final int DENSITY_DEVICE_STABLE;
field public static final int DENSITY_HIGH = 240; // 0xf0
field public static final int DENSITY_LOW = 120; // 0x78
field public static final int DENSITY_MEDIUM = 160; // 0xa0
@@ -53637,6 +54080,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 90a5dc7..27de913 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -192,7 +192,7 @@
package android.test.mock {
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public deprecated java.lang.String getDefaultBrowserPackageName(int);
method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 25b72c0..60274d7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -33,6 +33,7 @@
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -505,6 +506,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -880,6 +883,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1127,6 +1131,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -2619,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2677,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4636,6 +4655,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5532,6 +5552,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5550,6 +5571,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5790,6 +5812,7 @@
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+ method public void clearProfileOwner(android.content.ComponentName);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
@@ -5816,6 +5839,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5885,6 +5909,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6296,7 +6321,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6305,9 +6329,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -6511,8 +6532,9 @@
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_DEVICE_LOCKED = 210007; // 0x33457
- field public static final int TAG_DEVICE_UNLOCK_ATTEMPT = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
}
@@ -9955,7 +9977,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9964,13 +9986,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10074,6 +10101,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10133,6 +10165,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10168,6 +10201,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
@@ -13364,6 +13398,7 @@
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
+ method public java.util.UUID getUuid();
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isWakeUpSensor();
@@ -13378,11 +13413,13 @@
field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
@@ -13390,6 +13427,7 @@
field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+ field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13401,11 +13439,13 @@
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEART_BEAT = 31; // 0x1f
field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_LIGHT = 5; // 0x5
field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+ field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
field public static final int TYPE_POSE_6DOF = 28; // 0x1c
field public static final int TYPE_PRESSURE = 6; // 0x6
@@ -13413,11 +13453,27 @@
field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+ field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
field public static final int TYPE_STEP_COUNTER = 19; // 0x13
field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
}
+ public class SensorAdditionalInfo {
+ field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+ field public static final int TYPE_FRAME_END = 1; // 0x1
+ field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+ field public static final int TYPE_SAMPLING = 65540; // 0x10004
+ field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+ field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+ field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+ field public final float[] floatValues;
+ field public final int[] intValues;
+ field public final android.hardware.Sensor sensor;
+ field public final int serial;
+ field public final int type;
+ }
+
public class SensorEvent {
field public int accuracy;
field public android.hardware.Sensor sensor;
@@ -13425,6 +13481,14 @@
field public final float[] values;
}
+ public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+ ctor public SensorEventCallback();
+ method public void onAccuracyChanged(android.hardware.Sensor, int);
+ method public void onFlushCompleted(android.hardware.Sensor);
+ method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+ method public void onSensorChanged(android.hardware.SensorEvent);
+ }
+
public abstract interface SensorEventListener {
method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13446,6 +13510,7 @@
method public static void getAngleChange(float[], float[], float[]);
method public android.hardware.Sensor getDefaultSensor(int);
method public android.hardware.Sensor getDefaultSensor(int, boolean);
+ method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
method public static float getInclination(float[]);
method public static float[] getOrientation(float[], float[]);
method public static void getQuaternionFromVector(float[], float[]);
@@ -13453,6 +13518,8 @@
method public static void getRotationMatrixFromVector(float[], float[]);
method public java.util.List<android.hardware.Sensor> getSensorList(int);
method public deprecated int getSensors();
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+ method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
method public deprecated boolean registerListener(android.hardware.SensorListener, int);
method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13461,6 +13528,7 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
+ method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
method public deprecated void unregisterListener(android.hardware.SensorListener);
method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13525,6 +13593,12 @@
field public static final float STANDARD_GRAVITY = 9.80665f;
}
+ public static abstract class SensorManager.DynamicSensorConnectionCallback {
+ ctor public SensorManager.DynamicSensorConnectionCallback();
+ method public void onDynamicSensorConnected(android.hardware.Sensor);
+ method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+ }
+
public final class TriggerEvent {
field public android.hardware.Sensor sensor;
field public long timestamp;
@@ -19025,6 +19099,288 @@
method public static boolean isPresent();
}
+ public abstract interface GnssNmeaListener {
+ method public abstract void onNmeaReceived(long, java.lang.String);
+ }
+
+ public final class GnssStatus {
+ method public float getAzimuth(int);
+ method public int getConstellationType(int);
+ method public float getElevation(int);
+ method public int getNumSatellites();
+ method public int getPrn(int);
+ method public float getSnr(int);
+ method public boolean hasAlmanac(int);
+ method public boolean hasEphemeris(int);
+ method public boolean usedInFix(int);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract class GnssStatusCallback {
+ ctor public GnssStatusCallback();
+ method public void onFirstFix(int);
+ method public void onSatelliteStatusChanged(android.location.GnssStatus);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class GpsClock implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getBiasInNs();
+ method public double getBiasUncertaintyInNs();
+ method public double getDriftInNsPerSec();
+ method public double getDriftUncertaintyInNsPerSec();
+ method public long getFullBiasInNs();
+ method public short getLeapSecond();
+ method public long getTimeInNs();
+ method public long getTimeOfLastHwClockDiscontinuityInNs();
+ method public double getTimeUncertaintyInNs();
+ method public byte getType();
+ method public boolean hasBiasInNs();
+ method public boolean hasBiasUncertaintyInNs();
+ method public boolean hasDriftInNsPerSec();
+ method public boolean hasDriftUncertaintyInNsPerSec();
+ method public boolean hasFullBiasInNs();
+ method public boolean hasLeapSecond();
+ method public boolean hasTimeUncertaintyInNs();
+ method public void reset();
+ method public void resetBiasInNs();
+ method public void resetBiasUncertaintyInNs();
+ method public void resetDriftInNsPerSec();
+ method public void resetDriftUncertaintyInNsPerSec();
+ method public void resetFullBiasInNs();
+ method public void resetLeapSecond();
+ method public void resetTimeUncertaintyInNs();
+ method public void set(android.location.GpsClock);
+ method public void setBiasInNs(double);
+ method public void setBiasUncertaintyInNs(double);
+ method public void setDriftInNsPerSec(double);
+ method public void setDriftUncertaintyInNsPerSec(double);
+ method public void setFullBiasInNs(long);
+ method public void setLeapSecond(short);
+ method public void setTimeInNs(long);
+ method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+ method public void setTimeUncertaintyInNs(double);
+ method public void setType(byte);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
+ field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
+ field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
+ field public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+ }
+
+ public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method public double getAccumulatedDeltaRangeInMeters();
+ method public short getAccumulatedDeltaRangeState();
+ method public double getAccumulatedDeltaRangeUncertaintyInMeters();
+ method public double getAzimuthInDeg();
+ method public double getAzimuthUncertaintyInDeg();
+ method public int getBitNumber();
+ method public long getCarrierCycles();
+ method public float getCarrierFrequencyInHz();
+ method public double getCarrierPhase();
+ method public double getCarrierPhaseUncertainty();
+ method public double getCn0InDbHz();
+ method public double getCodePhaseInChips();
+ method public double getCodePhaseUncertaintyInChips();
+ method public double getDopplerShiftInHz();
+ method public double getDopplerShiftUncertaintyInHz();
+ method public double getElevationInDeg();
+ method public double getElevationUncertaintyInDeg();
+ method public byte getLossOfLock();
+ method public byte getMultipathIndicator();
+ method public byte getPrn();
+ method public double getPseudorangeInMeters();
+ method public double getPseudorangeRateCarrierInMetersPerSec();
+ method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
+ method public double getPseudorangeRateInMetersPerSec();
+ method public double getPseudorangeRateUncertaintyInMetersPerSec();
+ method public double getPseudorangeUncertaintyInMeters();
+ method public long getReceivedGpsTowInNs();
+ method public long getReceivedGpsTowUncertaintyInNs();
+ method public double getSnrInDb();
+ method public short getState();
+ method public short getTimeFromLastBitInMs();
+ method public double getTimeOffsetInNs();
+ method public boolean hasAzimuthInDeg();
+ method public boolean hasAzimuthUncertaintyInDeg();
+ method public boolean hasBitNumber();
+ method public boolean hasCarrierCycles();
+ method public boolean hasCarrierFrequencyInHz();
+ method public boolean hasCarrierPhase();
+ method public boolean hasCarrierPhaseUncertainty();
+ method public boolean hasCodePhaseInChips();
+ method public boolean hasCodePhaseUncertaintyInChips();
+ method public boolean hasDopplerShiftInHz();
+ method public boolean hasDopplerShiftUncertaintyInHz();
+ method public boolean hasElevationInDeg();
+ method public boolean hasElevationUncertaintyInDeg();
+ method public boolean hasPseudorangeInMeters();
+ method public boolean hasPseudorangeUncertaintyInMeters();
+ method public boolean hasSnrInDb();
+ method public boolean hasTimeFromLastBitInMs();
+ method public boolean isPseudorangeRateCorrected();
+ method public boolean isUsedInFix();
+ method public void reset();
+ method public void resetAzimuthInDeg();
+ method public void resetAzimuthUncertaintyInDeg();
+ method public void resetBitNumber();
+ method public void resetCarrierCycles();
+ method public void resetCarrierFrequencyInHz();
+ method public void resetCarrierPhase();
+ method public void resetCarrierPhaseUncertainty();
+ method public void resetCodePhaseInChips();
+ method public void resetCodePhaseUncertaintyInChips();
+ method public void resetDopplerShiftInHz();
+ method public void resetDopplerShiftUncertaintyInHz();
+ method public void resetElevationInDeg();
+ method public void resetElevationUncertaintyInDeg();
+ method public void resetPseudorangeInMeters();
+ method public void resetPseudorangeUncertaintyInMeters();
+ method public void resetSnrInDb();
+ method public void resetTimeFromLastBitInMs();
+ method public void set(android.location.GpsMeasurement);
+ method public void setAccumulatedDeltaRangeInMeters(double);
+ method public void setAccumulatedDeltaRangeState(short);
+ method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+ method public void setAzimuthInDeg(double);
+ method public void setAzimuthUncertaintyInDeg(double);
+ method public void setBitNumber(int);
+ method public void setCarrierCycles(long);
+ method public void setCarrierFrequencyInHz(float);
+ method public void setCarrierPhase(double);
+ method public void setCarrierPhaseUncertainty(double);
+ method public void setCn0InDbHz(double);
+ method public void setCodePhaseInChips(double);
+ method public void setCodePhaseUncertaintyInChips(double);
+ method public void setDopplerShiftInHz(double);
+ method public void setDopplerShiftUncertaintyInHz(double);
+ method public void setElevationInDeg(double);
+ method public void setElevationUncertaintyInDeg(double);
+ method public void setLossOfLock(byte);
+ method public void setMultipathIndicator(byte);
+ method public void setPrn(byte);
+ method public void setPseudorangeInMeters(double);
+ method public void setPseudorangeRateCarrierInMetersPerSec(double);
+ method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
+ method public void setPseudorangeRateInMetersPerSec(double);
+ method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+ method public void setPseudorangeUncertaintyInMeters(double);
+ method public void setReceivedGpsTowInNs(long);
+ method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setSnrInDb(double);
+ method public void setState(short);
+ method public void setTimeFromLastBitInMs(short);
+ method public void setTimeOffsetInNs(double);
+ method public void setUsedInFix(boolean);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+ field public static final short ADR_STATE_RESET = 2; // 0x2
+ field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+ field public static final short ADR_STATE_VALID = 1; // 0x1
+ field public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+ field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+ field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+ field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+ field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+ field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+ field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final short STATE_BIT_SYNC = 2; // 0x2
+ field public static final short STATE_CODE_LOCK = 1; // 0x1
+ field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+ field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+ field public static final short STATE_TOW_DECODED = 8; // 0x8
+ field public static final short STATE_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsMeasurementsEvent implements android.os.Parcelable {
+ ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+ method public int describeContents();
+ method public android.location.GpsClock getClock();
+ method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+ field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+ field public static final int STATUS_READY = 1; // 0x1
+ }
+
+ public static abstract class GpsMeasurementsEvent.Callback {
+ ctor public GpsMeasurementsEvent.Callback();
+ method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+ method public void onStatusChanged(int);
+ }
+
+ public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessage implements android.os.Parcelable {
+ method public int describeContents();
+ method public byte[] getData();
+ method public short getMessageId();
+ method public byte getPrn();
+ method public short getStatus();
+ method public short getSubmessageId();
+ method public byte getType();
+ method public void reset();
+ method public void set(android.location.GpsNavigationMessage);
+ method public void setData(byte[]);
+ method public void setMessageId(short);
+ method public void setPrn(byte);
+ method public void setStatus(short);
+ method public void setSubmessageId(short);
+ method public void setType(byte);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+ field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+ field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+ field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+ field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+ field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short STATUS_PARITY_PASSED = 1; // 0x1
+ field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+ field public static final short STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+ }
+
+ public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+ ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+ method public int describeContents();
+ method public android.location.GpsNavigationMessage getNavigationMessage();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+ field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+ field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+ field public static final int STATUS_READY = 1; // 0x1
+ }
+
+ public static abstract class GpsNavigationMessageEvent.Callback {
+ ctor public GpsNavigationMessageEvent.Callback();
+ method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+ method public void onStatusChanged(int);
+ }
+
+ public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+ }
+
public final class GpsSatellite {
method public float getAzimuth();
method public float getElevation();
@@ -19109,8 +19465,10 @@
}
public class LocationManager {
- method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
- method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener);
+ method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void clearTestProviderEnabled(java.lang.String);
@@ -19118,14 +19476,22 @@
method public void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
- method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+ method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+ method public int getGpsYearOfHardware();
method public android.location.Location getLastKnownLocation(java.lang.String);
method public android.location.LocationProvider getProvider(java.lang.String);
method public java.util.List<java.lang.String> getProviders(boolean);
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
method public boolean isProviderEnabled(java.lang.String);
- method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
- method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+ method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+ method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+ method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+ method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+ method public void removeNmeaListener(android.location.GnssNmeaListener);
method public void removeProximityAlert(android.app.PendingIntent);
method public void removeTestProvider(java.lang.String);
method public void removeUpdates(android.location.LocationListener);
@@ -19143,6 +19509,9 @@
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+ method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+ method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+ method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
field public static final java.lang.String GPS_PROVIDER = "gps";
field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19209,6 +19578,7 @@
field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+ field public static final int FLAG_LOW_LATENCY = 256; // 0x100
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -19328,6 +19698,7 @@
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
+ field public static final int ENCODING_IEC61937 = 13; // 0xd
field public static final int ENCODING_INVALID = 0; // 0x0
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -19523,6 +19894,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -19572,8 +19944,11 @@
public class AudioRecordConfiguration implements android.os.Parcelable {
method public int describeContents();
- method public int getAudioSessionId();
+ method public android.media.AudioDeviceInfo getAudioDevice();
+ method public int getClientAudioSessionId();
method public int getClientAudioSource();
+ method public android.media.AudioFormat getClientFormat();
+ method public android.media.AudioFormat getFormat();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.AudioRecordConfiguration> CREATOR;
}
@@ -19591,6 +19966,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -19605,6 +19982,7 @@
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
+ method public int getBufferCapacityInFrames();
method public int getBufferSizeInFrames();
method public int getChannelConfiguration();
method public int getChannelCount();
@@ -19626,6 +20004,7 @@
method public int getState();
method public int getStreamType();
method public boolean getTimestamp(android.media.AudioTimestamp);
+ method public int getUnderrunCount();
method public void pause() throws java.lang.IllegalStateException;
method public void play() throws java.lang.IllegalStateException;
method public void release();
@@ -19633,6 +20012,7 @@
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
+ method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
method public int setNotificationMarkerPosition(int);
method public int setPlaybackHeadPosition(int);
@@ -19744,6 +20124,16 @@
ctor public DeniedByServerException(java.lang.String);
}
+ public abstract class DrmInitData {
+ ctor public DrmInitData();
+ method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+ }
+
+ public static final class DrmInitData.SchemeInitData {
+ field public final byte[] data;
+ field public final java.lang.String mimeType;
+ }
+
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
method public double getAltitude(double);
@@ -20233,6 +20623,24 @@
field public static final int VP8Level_Version2 = 4; // 0x4
field public static final int VP8Level_Version3 = 8; // 0x8
field public static final int VP8ProfileMain = 1; // 0x1
+ field public static final int VP9Level1 = 0; // 0x0
+ field public static final int VP9Level11 = 1; // 0x1
+ field public static final int VP9Level2 = 2; // 0x2
+ field public static final int VP9Level21 = 4; // 0x4
+ field public static final int VP9Level3 = 8; // 0x8
+ field public static final int VP9Level31 = 16; // 0x10
+ field public static final int VP9Level4 = 32; // 0x20
+ field public static final int VP9Level41 = 64; // 0x40
+ field public static final int VP9Level5 = 128; // 0x80
+ field public static final int VP9Level51 = 256; // 0x100
+ field public static final int VP9Level52 = 512; // 0x200
+ field public static final int VP9Level6 = 1024; // 0x400
+ field public static final int VP9Level61 = 2048; // 0x800
+ field public static final int VP9Level62 = 4096; // 0x1000
+ field public static final int VP9Profile0 = 0; // 0x0
+ field public static final int VP9Profile1 = 1; // 0x1
+ field public static final int VP9Profile2 = 2; // 0x2
+ field public static final int VP9Profile3 = 3; // 0x3
field public int level;
field public int profile;
}
@@ -20416,6 +20824,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.DrmInitData getDrmInitData();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
method public int getSampleFlags();
@@ -20460,6 +20869,16 @@
method public final void setInteger(java.lang.String, int);
method public final void setLong(java.lang.String, long);
method public final void setString(java.lang.String, java.lang.String);
+ field public static final int COLOR_RANGE_FULL = 1; // 0x1
+ field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+ field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+ field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+ field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+ field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+ field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+ field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+ field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -20475,6 +20894,9 @@
field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+ field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+ field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+ field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
field public static final java.lang.String KEY_COMPLEXITY = "complexity";
field public static final java.lang.String KEY_DURATION = "durationUs";
field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
@@ -22100,6 +22522,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22178,6 +22601,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22494,7 +22918,8 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onInputUpdated(java.lang.String);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22502,7 +22927,7 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -22573,7 +22998,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -22765,6 +23190,7 @@
field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+ field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
@@ -22802,6 +23228,7 @@
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+ method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22810,7 +23237,7 @@
method public boolean importFile(int, android.os.ParcelFileDescriptor);
method public boolean open(android.hardware.usb.UsbDeviceConnection);
method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
- method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+ method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
}
@@ -22841,23 +23268,31 @@
method public final int getAssociationDesc();
method public final int getAssociationType();
method public final int getCompressedSize();
+ method public final long getCompressedSizeLong();
method public final long getDateCreated();
method public final long getDateModified();
method public final int getFormat();
method public final int getImagePixDepth();
+ method public final long getImagePixDepthLong();
method public final int getImagePixHeight();
+ method public final long getImagePixHeightLong();
method public final int getImagePixWidth();
+ method public final long getImagePixWidthLong();
method public final java.lang.String getKeywords();
method public final java.lang.String getName();
method public final int getObjectHandle();
method public final int getParent();
method public final int getProtectionStatus();
method public final int getSequenceNumber();
+ method public final long getSequenceNumberLong();
method public final int getStorageId();
method public final int getThumbCompressedSize();
+ method public final long getThumbCompressedSizeLong();
method public final int getThumbFormat();
method public final int getThumbPixHeight();
+ method public final long getThumbPixHeightLong();
method public final int getThumbPixWidth();
+ method public final long getThumbPixWidthLong();
}
public static class MtpObjectInfo.Builder {
@@ -22866,24 +23301,24 @@
method public android.mtp.MtpObjectInfo build();
method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
- method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
method public android.mtp.MtpObjectInfo.Builder setFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
- method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+ method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
- method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+ method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
}
public final class MtpStorageInfo {
@@ -28130,6 +28565,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -28561,6 +29000,7 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -28720,6 +29160,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -28827,6 +29268,8 @@
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+ field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+ field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
}
public abstract class Vibrator {
@@ -29184,6 +29627,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -31181,7 +31626,9 @@
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+ method public static boolean isTreeUri(android.net.Uri);
method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -31207,6 +31654,7 @@
field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+ field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
@@ -31254,6 +31702,7 @@
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+ method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -31633,6 +32082,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -32296,6 +32746,7 @@
public class VoicemailContract {
field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+ field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -32310,8 +32761,13 @@
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+ field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+ field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+ field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+ field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+ field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -32409,6 +32865,7 @@
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
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);
@@ -32424,9 +32881,12 @@
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
method public void generateMipmaps();
+ method public java.nio.ByteBuffer getByteBuffer();
method public int getBytesSize();
method public android.renderscript.Element getElement();
+ method public long getStride();
method public android.view.Surface getSurface();
+ method public long getTimeStamp();
method public android.renderscript.Type getType();
method public int getUsage();
method public void ioReceive();
@@ -35367,6 +35827,30 @@
field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
}
+ public abstract class CallScreeningService extends android.app.Service {
+ ctor public CallScreeningService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onScreenCall(android.telecom.Call.Details);
+ method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+ }
+
+ public static class CallScreeningService.CallResponse {
+ method public boolean getDisallowCall();
+ method public boolean getRejectCall();
+ method public boolean getSkipCallLog();
+ method public boolean getSkipNotification();
+ }
+
+ public static class CallScreeningService.CallResponse.Builder {
+ ctor public CallScreeningService.CallResponse.Builder();
+ method public android.telecom.CallScreeningService.CallResponse build();
+ method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+ method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+ }
+
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
@@ -35606,6 +36090,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Call);
method public void onCanAddCallChanged(boolean);
+ method public void onSilenceRinger();
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -35866,6 +36351,7 @@
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -36017,6 +36503,7 @@
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+ field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -36742,7 +37229,7 @@
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
method public T getActivity();
@@ -36750,14 +37237,14 @@
method public void setActivityIntent(android.content.Intent);
}
- public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
ctor public ActivityTestCase();
method protected android.app.Activity getActivity();
method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
method protected void setActivity(android.app.Activity);
}
- public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+ public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
ctor public ActivityUnitTestCase(java.lang.Class<T>);
method public T getActivity();
method public int getFinishedActivityRequest();
@@ -36770,7 +37257,7 @@
method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
}
- public class AndroidTestCase extends junit.framework.TestCase {
+ public deprecated class AndroidTestCase extends junit.framework.TestCase {
ctor public AndroidTestCase();
method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -36782,7 +37269,7 @@
field protected android.content.Context mContext;
}
- public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+ public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
ctor public AndroidTestRunner();
method public void addTestListener(junit.framework.TestListener);
method public void clearTestListeners();
@@ -36803,7 +37290,7 @@
method public void testStarted(java.lang.String);
}
- public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
ctor public ApplicationTestCase(java.lang.Class<T>);
method protected final void createApplication();
method public T getApplication();
@@ -36821,10 +37308,10 @@
ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
}
- public abstract class FlakyTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
}
- public class InstrumentationTestCase extends junit.framework.TestCase {
+ public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
ctor public InstrumentationTestCase();
method public android.app.Instrumentation getInstrumentation();
method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36837,7 +37324,7 @@
method public void sendRepeatedKeys(int...);
}
- public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+ public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
ctor public InstrumentationTestRunner();
method public junit.framework.TestSuite getAllTests();
method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36856,14 +37343,14 @@
field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
}
- public class InstrumentationTestSuite extends junit.framework.TestSuite {
+ public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
ctor public InstrumentationTestSuite(android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
method public void addTestSuite(java.lang.Class);
}
- public class IsolatedContext extends android.content.ContextWrapper {
+ public deprecated class IsolatedContext extends android.content.ContextWrapper {
ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
}
@@ -36873,7 +37360,7 @@
method public T getLoaderResultSynchronously(android.content.Loader<T>);
}
- public final class MoreAsserts {
+ public final deprecated class MoreAsserts {
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -36912,7 +37399,7 @@
method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
}
- public abstract interface PerformanceTestCase {
+ public abstract deprecated interface PerformanceTestCase {
method public abstract boolean isPerformanceOnly();
method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
}
@@ -36941,7 +37428,7 @@
method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public class RenamingDelegatingContext extends android.content.ContextWrapper {
+ public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
method public java.lang.String getDatabasePrefix();
@@ -36950,7 +37437,7 @@
method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
}
- public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+ public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
ctor public ServiceTestCase(java.lang.Class<T>);
method protected android.os.IBinder bindService(android.content.Intent);
method public android.app.Application getApplication();
@@ -36963,23 +37450,23 @@
method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
}
- public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+ public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
method public T getActivity();
method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
}
- public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+ public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
ctor public SyncBaseInstrumentation();
method protected void cancelSyncsandDisableAutoSync();
method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
}
- public abstract interface TestSuiteProvider {
+ public abstract deprecated interface TestSuiteProvider {
method public abstract junit.framework.TestSuite getTestSuite();
}
- public class TouchUtils {
+ public deprecated class TouchUtils {
ctor public TouchUtils();
method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -37014,10 +37501,10 @@
method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
}
- public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
}
- public class ViewAsserts {
+ public deprecated class ViewAsserts {
method public static void assertBaselineAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View);
method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -37042,11 +37529,11 @@
package android.test.mock {
- public class MockApplication extends android.app.Application {
+ public deprecated class MockApplication extends android.app.Application {
ctor public MockApplication();
}
- public class MockContentProvider extends android.content.ContentProvider {
+ public deprecated class MockContentProvider extends android.content.ContentProvider {
ctor protected MockContentProvider();
ctor public MockContentProvider(android.content.Context);
ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -37058,13 +37545,13 @@
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
}
- public class MockContentResolver extends android.content.ContentResolver {
+ public deprecated class MockContentResolver extends android.content.ContentResolver {
ctor public MockContentResolver();
ctor public MockContentResolver(android.content.Context);
method public void addProvider(java.lang.String, android.content.ContentProvider);
}
- public class MockContext extends android.content.Context {
+ public deprecated class MockContext extends android.content.Context {
ctor public MockContext();
method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
method public int checkCallingOrSelfPermission(java.lang.String);
@@ -37165,7 +37652,7 @@
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class MockCursor implements android.database.Cursor {
+ public deprecated class MockCursor implements android.database.Cursor {
ctor public MockCursor();
method public void close();
method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -37210,13 +37697,13 @@
method public void unregisterDataSetObserver(android.database.DataSetObserver);
}
- public class MockDialogInterface implements android.content.DialogInterface {
+ public deprecated class MockDialogInterface implements android.content.DialogInterface {
ctor public MockDialogInterface();
method public void cancel();
method public void dismiss();
}
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
method public void addPackageToPreferred(java.lang.String);
method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -37304,7 +37791,7 @@
method public void verifyPendingInstall(int, int);
}
- public class MockResources extends android.content.res.Resources {
+ public deprecated class MockResources extends android.content.res.Resources {
ctor public MockResources();
}
@@ -37345,19 +37832,19 @@
package android.test.suitebuilder.annotation {
- public abstract class LargeTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
}
- public abstract class MediumTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
}
- public abstract class SmallTest implements java.lang.annotation.Annotation {
+ public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
}
- public abstract class Smoke implements java.lang.annotation.Annotation {
+ public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
}
- public abstract class Suppress implements java.lang.annotation.Annotation {
+ public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
}
}
@@ -39411,6 +39898,7 @@
field public static final int DENSITY_420 = 420; // 0x1a4
field public static final int DENSITY_560 = 560; // 0x230
field public static final int DENSITY_DEFAULT = 160; // 0xa0
+ field public static final int DENSITY_DEVICE_STABLE;
field public static final int DENSITY_HIGH = 240; // 0xf0
field public static final int DENSITY_LOW = 120; // 0x78
field public static final int DENSITY_MEDIUM = 160; // 0xa0
@@ -50856,6 +51344,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 6b7961e..2c6729d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -201,7 +201,7 @@
package android.test.mock {
- public class MockPackageManager extends android.content.pm.PackageManager {
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public deprecated java.lang.String getDefaultBrowserPackageName(int);
method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 72e8c3b..ba93b2a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -47,7 +47,6 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -79,7 +78,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.List;
public class Am extends BaseCommand {
@@ -159,6 +157,7 @@
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
" am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
" am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
@@ -167,7 +166,7 @@
" am stack info <STACK_ID>\n" +
" am task lock <TASK_ID>\n" +
" am task lock stop\n" +
- " am task resizeable <TASK_ID> [true|false]\n" +
+ " am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]\n" +
" am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
@@ -324,7 +323,8 @@
"\n" +
"am task lock stop: end the current task lock.\n" +
"\n" +
- "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
+ "am task resizeable: change resizeable mode of <TASK_ID>.\n" +
+ " 0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)\n" +
"\n" +
"am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" +
" Forces the task to be resizeable and creates a stack if no existing stack\n" +
@@ -1688,6 +1688,9 @@
case "resize":
runStackResize();
break;
+ case "resize-animated":
+ runStackResizeAnimated();
+ break;
case "resize-docked-stack":
runStackResizeDocked();
break;
@@ -1756,7 +1759,18 @@
System.err.println("Error: invalid input bounds");
return;
}
- resizeStack(stackId, bounds, 0);
+ resizeStack(stackId, bounds, 0, false);
+ }
+
+ private void runStackResizeAnimated() throws Exception {
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ final Rect bounds = getBounds();
+ if (bounds == null) {
+ System.err.println("Error: invalid input bounds");
+ return;
+ }
+ resizeStack(stackId, bounds, 0, true);
}
private void runStackResizeDocked() throws Exception {
@@ -1773,14 +1787,15 @@
}
}
- private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
+ private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate)
+ throws Exception {
if (bounds == null) {
showError("Error: invalid input bounds");
return;
}
try {
- mAm.resizeStack(stackId, bounds, false);
+ mAm.resizeStack(stackId, bounds, false, false, animate);
Thread.sleep(delayMs);
} catch (RemoteException e) {
showError("Error: resizing stack " + e);
@@ -1894,7 +1909,7 @@
maxChange = Math.min(stepSize, currentPoint - minPoint);
currentPoint -= maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
System.out.println("Growing docked stack side=" + side);
@@ -1902,7 +1917,7 @@
maxChange = Math.min(stepSize, maxPoint - currentPoint);
currentPoint += maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
System.out.println("Back to Original size side=" + side);
@@ -1910,7 +1925,7 @@
maxChange = Math.min(stepSize, currentPoint - startPoint);
currentPoint -= maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
}
@@ -1971,10 +1986,10 @@
final String taskIdStr = nextArgRequired();
final int taskId = Integer.valueOf(taskIdStr);
final String resizeableStr = nextArgRequired();
- final boolean resizeable = Boolean.valueOf(resizeableStr);
+ final int resizeableMode = Integer.valueOf(resizeableStr);
try {
- mAm.setTaskResizeable(taskId, resizeable);
+ mAm.setTaskResizeable(taskId, resizeableMode);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bc17f8..c96cca2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,6 +17,7 @@
package android.accessibilityservice;
import android.accessibilityservice.GestureDescription.MotionEventGenerator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
@@ -29,6 +30,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -46,10 +48,13 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
- * An accessibility service runs in the background and receives callbacks by the system
+ * Accessibility services are intended to assist users with disabilities in using
+ * Android devices and apps. They run in the background and receive callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
* in the user interface, for example, the focus has changed, a button has been clicked,
* etc. Such a service can optionally request the capability for querying the content
@@ -66,22 +71,31 @@
* <h3>Lifecycle</h3>
* <p>
* The lifecycle of an accessibility service is managed exclusively by the system and
- * follows the established service life cycle. Additionally, starting or stopping an
- * accessibility service is triggered exclusively by an explicit user action through
- * enabling or disabling it in the device settings. After the system binds to a service it
- * calls {@link AccessibilityService#onServiceConnected()}. This method can be
- * overriden by clients that want to perform post binding setup.
+ * follows the established service life cycle. Starting an accessibility service is triggered
+ * exclusively by the user explicitly turning the service on in device settings. After the system
+ * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
+ * be overriden by clients that want to perform post binding setup.
+ * </p>
+ * <p>
+ * An accessibility service stops either when the user turns it off in device settings or when
+ * it calls {@link AccessibilityService#disableSelf()}.
* </p>
* <h3>Declaration</h3>
* <p>
- * An accessibility is declared as any other service in an AndroidManifest.xml but it
- * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Additionally an accessibility service must request the
- * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
- * that only the system
- * can bind to it. Failure to declare this intent will cause the system to ignore the
- * accessibility service. Following is an example declaration:
+ * An accessibility is declared as any other service in an AndroidManifest.xml, but it
+ * must do two things:
+ * <ul>
+ * <ol>
+ * Specify that it handles the "android.accessibilityservice.AccessibilityService"
+ * {@link android.content.Intent}.
+ * </ol>
+ * <ol>
+ * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
+ * ensure that only the system can bind to it.
+ * </ol>
+ * </ul>
+ * If either of these items is missing, the system will ignore the accessibility service.
+ * Following is an example declaration:
* </p>
* <pre> <service android:name=".MyAccessibilityService"
* android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
@@ -135,48 +149,24 @@
* </ul>
* <h3>Retrieving window content</h3>
* <p>
- * A service can specify in its declaration that it can retrieve the active window
- * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * A service can specify in its declaration that it can retrieve window
+ * content which is represented as a tree of {@link AccessibilityWindowInfo} and
+ * {@link AccessibilityNodeInfo} objects. Note that
* declaring this capability requires that the service declares its configuration via
* an XML resource referenced by {@link #SERVICE_META_DATA}.
* </p>
* <p>
- * For security purposes an accessibility service can retrieve only the content of the
- * currently active window. The currently active window is defined as the window from
- * which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * In other words, the last window that was shown or the last window that the user has touched
- * during touch exploration.
- * </p>
- * <p>
- * The entry point for retrieving window content is through calling
- * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
- * event of the above types or a previous event from the same window
- * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
- * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
- * window content which represented as a tree of such objects.
+ * Window content may be retrieved with
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
+ * {@link AccessibilityService#findFocus(int)},
+ * {@link AccessibilityService#getWindows()}, or
+ * {@link AccessibilityService#getRootInActiveWindow()}.
* </p>
* <p class="note">
* <strong>Note</strong> An accessibility service may have requested to be notified for
- * a subset of the event types, thus be unaware that the active window has changed. Therefore
- * accessibility service that would like to retrieve window content should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track for the active
- * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
- * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
- * methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
- * active window has changed and the service did not get the accessibility event yet. Note
- * that it is possible to have a retrieval method failing even adopting the strategy
- * specified in the previous bullet because the accessibility event dispatch is asynchronous
- * and crosses process boundaries.
- * </li>
- * </ul>
+ * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
+ * possible for a node to contain outdated information because the window content may change at any
+ * time.
* </p>
* <h3>Notification strategy</h3>
* <p>
@@ -328,7 +318,6 @@
* android:settingsActivity="foo.bar.TestBackActivity"
* android:canRetrieveWindowContent="true"
* android:canRequestTouchExplorationMode="true"
- * android:canRequestEnhancedWebAccessibility="true"
* . . .
* /></pre>
*/
@@ -378,9 +367,26 @@
public boolean onKeyEvent(KeyEvent event);
public void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY);
+ public void onSoftKeyboardShowModeChanged(int showMode);
public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
+ /**
+ * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
+ public @interface SoftKeyboardShowMode {};
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
private int mConnectionId;
private AccessibilityServiceInfo mInfo;
@@ -390,6 +396,7 @@
private WindowManager mWindowManager;
private MagnificationController mMagnificationController;
+ private SoftKeyboardController mSoftKeyboardController;
private int mGestureStatusCallbackSequence;
@@ -528,6 +535,14 @@
* is currently touching or the window with input focus, if the user is not
* touching any window.
* <p>
+ * The currently active window is defined as the window that most recently fired one
+ * of the following events:
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+ * In other words, the last window shown that also has input focus.
+ * </p>
+ * <p>
* <strong>Note:</strong> In order to access the root node your service has
* to declare the capability to retrieve window content by setting the
* {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -541,8 +556,8 @@
}
/**
- * This method allows accessibility service turn itself off
- * and the service will become disabled from the Settings.
+ * Disables the service. After calling this method, the service will be disabled and settings
+ * will show that it is turned off.
*/
public final void disableSelf() {
final IAccessibilityServiceConnection connection =
@@ -570,10 +585,12 @@
*/
@NonNull
public final MagnificationController getMagnificationController() {
- if (mMagnificationController == null) {
- mMagnificationController = new MagnificationController(this);
+ synchronized (mLock) {
+ if (mMagnificationController == null) {
+ mMagnificationController = new MagnificationController(this, mLock);
+ }
+ return mMagnificationController;
}
- return mMagnificationController;
}
/**
@@ -677,17 +694,21 @@
* first magnification listener.
*/
private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
+ private final Object mLock;
- MagnificationController(@NonNull AccessibilityService service) {
+ MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
mService = service;
+ mLock = lock;
}
/**
* Called when the service is connected.
*/
void onServiceConnected() {
- if (mListeners != null && !mListeners.isEmpty()) {
- setMagnificationCallbackEnabled(true);
+ synchronized (mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -714,17 +735,19 @@
*/
public void addListener(@NonNull OnMagnificationChangedListener listener,
@Nullable Handler handler) {
- if (mListeners == null) {
- mListeners = new ArrayMap<>();
- }
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
- final boolean shouldEnableCallback = mListeners.isEmpty();
- mListeners.put(listener, handler);
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
- if (shouldEnableCallback) {
- // This may fail if the service is not connected yet, but if we
- // still have listeners when it connects then we can try again.
- setMagnificationCallbackEnabled(true);
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we
+ // still have listeners when it connects then we can try again.
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -741,19 +764,21 @@
return false;
}
- final int keyIndex = mListeners.indexOfKey(listener);
- final boolean hasKey = keyIndex >= 0;
- if (hasKey) {
- mListeners.removeAt(keyIndex);
- }
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
- if (hasKey && mListeners.isEmpty()) {
- // We just removed the last listener, so we don't need
- // callbacks from the service anymore.
- setMagnificationCallbackEnabled(false);
- }
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need
+ // callbacks from the service anymore.
+ setMagnificationCallbackEnabled(false);
+ }
- return hasKey;
+ return hasKey;
+ }
}
private void setMagnificationCallbackEnabled(boolean enabled) {
@@ -775,17 +800,19 @@
*/
void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
final float centerX, final float centerY) {
- if (mListeners == null || mListeners.isEmpty()) {
- Slog.d(LOG_TAG, "Received magnification changed "
- + "callback with no listeners registered!");
- setMagnificationCallbackEnabled(false);
- return;
- }
+ final ArrayMap<OnMagnificationChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received magnification changed "
+ + "callback with no listeners registered!");
+ setMagnificationCallbackEnabled(false);
+ return;
+ }
- // Listeners may remove themselves. Perform a shallow copy to avoid
- // concurrent modification.
- final ArrayMap<OnMagnificationChangedListener, Handler> entries =
- new ArrayMap<>(mListeners);
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
for (int i = 0, count = entries.size(); i < count; i++) {
final OnMagnificationChangedListener listener = entries.keyAt(i);
@@ -1018,6 +1045,243 @@
}
/**
+ * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
+ * show mode.
+ *
+ * @return the soft keyboard controller
+ */
+ @NonNull
+ public final SoftKeyboardController getSoftKeyboardController() {
+ synchronized (mLock) {
+ if (mSoftKeyboardController == null) {
+ mSoftKeyboardController = new SoftKeyboardController(this, mLock);
+ }
+ return mSoftKeyboardController;
+ }
+ }
+
+ private void onSoftKeyboardShowModeChanged(int showMode) {
+ if (mSoftKeyboardController != null) {
+ mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
+ }
+ }
+
+ /**
+ * Used to control and query the soft keyboard show mode.
+ */
+ public static final class SoftKeyboardController {
+ private final AccessibilityService mService;
+
+ /**
+ * Map of listeners to their handlers. Lazily created when adding the first
+ * soft keyboard change listener.
+ */
+ private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
+ private final Object mLock;
+
+ SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
+ mService = service;
+ mLock = lock;
+ }
+
+ /**
+ * Called when the service is connected.
+ */
+ void onServiceConnected() {
+ synchronized(mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Adds the specified change listener to the list of show mode change listeners. The
+ * callback will occur on the service's main thread. Listener is not called on registration.
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ addOnShowModeChangedListener(listener, null);
+ }
+
+ /**
+ * Adds the specified change listener to the list of soft keyboard show mode change
+ * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
+ * services's main thread if the handler is {@code null}.
+ *
+ * @param listener the listener to add, must be non-null
+ * @param handler the handler on which to callback should execute, or {@code null} to
+ * execute on the service's main thread
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
+ @Nullable Handler handler) {
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
+
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
+
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we still have
+ // listeners when it connects, we can try again.
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Removes all instances of the specified change listener from teh list of magnification
+ * change listeners.
+ *
+ * @param listener the listener to remove, must be non-null
+ * @return {@code true} if at least one instance of the listener was removed
+ */
+ public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ if (mListeners == null) {
+ return false;
+ }
+
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
+
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need callbacks from the
+ // service anymore.
+ setSoftKeyboardCallbackEnabled(false);
+ }
+
+ return hasKey;
+ }
+ }
+
+ private void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setSoftKeyboardCallbackEnabled(enabled);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * Dispatches the soft keyboard show mode change to any registered listeners. This should
+ * be called on the service's main thread.
+ */
+ void dispatchSoftKeyboardShowModeChanged(final int showMode) {
+ final ArrayMap<OnShowModeChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+ + " with no listeners registered!");
+ setSoftKeyboardCallbackEnabled(false);
+ return;
+ }
+
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
+
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final OnShowModeChangedListener listener = entries.keyAt(i);
+ final Handler handler = entries.valueAt(i);
+ if (handler != null) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onShowModeChanged(SoftKeyboardController.this, showMode);
+ }
+ });
+ } else {
+ // We're already on the main thread, just run the listener.
+ listener.onShowModeChanged(this, showMode);
+ }
+ }
+ }
+
+ /**
+ * Returns the show mode of the soft keyboard. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @return the current soft keyboard show mode
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ @SoftKeyboardShowMode
+ public int getShowMode() {
+ try {
+ return Settings.Secure.getInt(mService.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+ } catch (Settings.SettingNotFoundException e) {
+ Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
+ // The settings hasn't been changed yet, so it's value is null. Return the default.
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the soft keyboard show mode. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+ * The lastto this method will be honored, regardless of any previous calls (including those
+ * made by other AccessibilityServices).
+ * <p>
+ * <strong>Note:</strong> If the service is not yet conected (e.g.
+ * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+ * service has been disconnected, this method will hav no effect and return {@code false}.
+ *
+ * @param showMode the new show mode for the soft keyboard
+ * @return {@code true} on success
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ return connection.setSoftKeyboardShowMode(showMode);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Listener for changes in the soft keyboard show mode.
+ */
+ public interface OnShowModeChangedListener {
+ /**
+ * Called when the soft keyboard behavior changes. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @param controller the soft keyboard controller
+ * @param showMode the current soft keyboard show mode
+ */
+ void onShowModeChanged(@NonNull SoftKeyboardController controller,
+ @SoftKeyboardShowMode int showMode);
+ }
+ }
+
+ /**
* Performs a global action. Such an action can be performed
* at any moment regardless of the current application or user
* location in that application. For example going back, going
@@ -1054,7 +1318,7 @@
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
* Also the service has to opt-in to retrieve the interactive windows by
* setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
- * flag.Otherwise, the search will be performed only in the active window.
+ * flag. Otherwise, the search will be performed only in the active window.
* </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
@@ -1191,6 +1455,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
}
@@ -1212,7 +1481,8 @@
private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
private static final int DO_ON_KEY_EVENT = 6;
private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
- private static final int DO_GESTURE_COMPLETE = 8;
+ private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
+ private static final int DO_GESTURE_COMPLETE = 9;
private final HandlerCaller mCaller;
@@ -1271,6 +1541,12 @@
mCaller.sendMessage(message);
}
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ final Message message =
+ mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
+ mCaller.sendMessage(message);
+ }
+
public void onPerformGestureResult(int sequence, boolean successfully) {
Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
successfully ? 1 : 0);
@@ -1361,6 +1637,11 @@
mCallback.onMagnificationChanged(region, scale, centerX, centerY);
} return;
+ case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
+ final int showMode = (int) message.arg1;
+ mCallback.onSoftKeyboardShowModeChanged(showMode);
+ } return;
+
case DO_GESTURE_COMPLETE: {
final boolean successfully = message.arg2 == 1;
mCallback.onPerformGestureResult(message.arg1, successfully);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6280542..ef05d6f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -43,5 +43,7 @@
void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
+ void onSoftKeyboardShowModeChanged(int showMode);
+
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e58ef2f..d5e8a11 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -84,5 +84,9 @@
void setMagnificationCallbackEnabled(boolean enabled);
+ boolean setSoftKeyboardShowMode(int showMode);
+
+ void setSoftKeyboardCallbackEnabled(boolean enabled);
+
void sendMotionEvents(int sequence, in ParceledListSlice events);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11154f2..dc3f64a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4397,7 +4397,7 @@
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
+ fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -4629,7 +4629,7 @@
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
result = ActivityManagerNative.getDefault()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken,
@@ -4700,7 +4700,7 @@
if (mParent == null) {
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
return ActivityManagerNative.getDefault()
.startNextMatchingActivity(mToken, intent, options);
} catch (RemoteException e) {
@@ -5128,7 +5128,7 @@
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
try {
if (resultData != null) {
- resultData.prepareToLeaveProcess();
+ resultData.prepareToLeaveProcess(this);
}
if (ActivityManagerNative.getDefault()
.finishActivity(mToken, resultCode, resultData, finishTask)) {
@@ -5355,7 +5355,7 @@
@PendingIntent.Flags int flags) {
String packageName = getPackageName();
try {
- data.prepareToLeaveProcess();
+ data.prepareToLeaveProcess(this);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
@@ -6335,10 +6335,10 @@
resultData = mResultData;
}
if (resultData != null) {
- resultData.prepareToLeaveProcess();
+ resultData.prepareToLeaveProcess(this);
}
try {
- upIntent.prepareToLeaveProcess();
+ upIntent.prepareToLeaveProcess(this);
return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
resultCode, resultData);
} catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 420bf31..82170d1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -564,8 +564,7 @@
* there isn't a display gap.
*/
public static boolean preserveWindowOnTaskMove(int stackId) {
- return stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
+ return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
}
/**
@@ -616,6 +615,14 @@
public static boolean keepVisibleDeadAppWindowOnScreen(int stackId) {
return stackId != PINNED_STACK_ID;
}
+
+ /**
+ * Returns true if the backdrop on the client side should match the frame of the window.
+ * Returns false, if the backdrop should be fullscreen.
+ */
+ public static boolean useWindowFrameForBackdrop(int stackId) {
+ return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
+ }
}
/**
@@ -1188,6 +1195,12 @@
*/
public Rect bounds;
+ /**
+ * True if the task can go in the docked stack.
+ * @hide
+ */
+ public boolean isDockable;
+
public RecentTaskInfo() {
}
@@ -1231,6 +1244,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeInt(isDockable ? 1 : 0);
}
public void readFromParcel(Parcel source) {
@@ -1253,6 +1267,7 @@
numActivities = source.readInt();
bounds = source.readInt() > 0 ?
Rect.CREATOR.createFromParcel(source) : null;
+ isDockable = source.readInt() == 1;
}
public static final Creator<RecentTaskInfo> CREATOR
@@ -1437,6 +1452,12 @@
*/
public long lastActiveTime;
+ /**
+ * True if the task can go in the docked stack.
+ * @hide
+ */
+ public boolean isDockable;
+
public RunningTaskInfo() {
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 42ff8e8..138ff6d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -816,7 +816,9 @@
r = Rect.CREATOR.createFromParcel(data);
}
final boolean allowResizeInDockedMode = data.readInt() == 1;
- resizeStack(stackId, r, allowResizeInDockedMode);
+ final boolean preserveWindows = data.readInt() == 1;
+ final boolean animate = data.readInt() == 1;
+ resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate);
reply.writeNoException();
return true;
}
@@ -2585,9 +2587,9 @@
case SET_TASK_RESIZEABLE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- int taskId = data.readInt();
- boolean resizeable = (data.readInt() == 1) ? true : false;
- setTaskResizeable(taskId, resizeable);
+ final int taskId = data.readInt();
+ final int resizeableMode = data.readInt();
+ setTaskResizeable(taskId, resizeableMode);
reply.writeNoException();
return true;
}
@@ -3815,9 +3817,8 @@
return res;
}
@Override
- public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
- throws RemoteException
- {
+ public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3829,6 +3830,8 @@
data.writeInt(0);
}
data.writeInt(allowResizeInDockedMode ? 1 : 0);
+ data.writeInt(preserveWindows ? 1 : 0);
+ data.writeInt(animate ? 1 : 0);
mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -6304,12 +6307,12 @@
}
@Override
- public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException {
+ public void setTaskResizeable(int taskId, int resizeableMode) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(resizeable ? 1 : 0);
+ data.writeInt(resizeableMode);
mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e7457c..99c275c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,6 +56,7 @@
import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.DropBoxManager;
@@ -4659,6 +4660,16 @@
}
}
+ /**
+ * Public entrypoint to stop profiling. This is required to end profiling when the app crashes,
+ * so that profiler data won't be lost.
+ *
+ * @hide
+ */
+ public void stopProfiling() {
+ mProfiler.stopProfiling();
+ }
+
static final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
if (managed) {
try {
@@ -4959,16 +4970,22 @@
}
/**
- * For apps targetting SDK Honeycomb or later, we don't allow
- * network usage on the main event loop / UI thread.
- *
- * Note to those grepping: this is what ultimately throws
- * NetworkOnMainThreadException ...
+ * For apps targetting Honeycomb or later, we don't allow network usage
+ * on the main event loop / UI thread. This is what ultimately throws
+ * {@link NetworkOnMainThreadException}.
*/
- if (data.appInfo.targetSdkVersion > 9) {
+ if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
StrictMode.enableDeathOnNetwork();
}
+ /**
+ * For apps targetting N or later, we don't allow file:// Uri exposure.
+ * This is what ultimately throws {@link FileUriExposedException}.
+ */
+ if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+
NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(
(data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fab3740..0d6e93d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -752,7 +752,7 @@
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
+ fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -773,7 +773,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
@@ -790,7 +790,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -805,7 +805,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -822,7 +822,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -839,7 +839,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -856,7 +856,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -919,7 +919,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions, appOp,
@@ -933,7 +933,7 @@
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
@@ -955,7 +955,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -1006,7 +1006,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions,
@@ -1022,7 +1022,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1058,7 +1058,7 @@
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1077,7 +1077,7 @@
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
@@ -1090,7 +1090,7 @@
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1105,7 +1105,7 @@
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
@@ -1140,7 +1140,7 @@
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1159,7 +1159,7 @@
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, user.getIdentifier());
} catch (RemoteException e) {
@@ -1262,7 +1262,7 @@
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
@@ -1291,7 +1291,7 @@
private boolean stopServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1339,7 +1339,7 @@
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 22de2ff..cefbb80 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -146,8 +146,8 @@
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException;
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
- throws RemoteException;
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) throws RemoteException;
/**
* Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
@@ -530,7 +530,7 @@
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
- public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
+ public void setTaskResizeable(int taskId, int resizeableMode) throws RemoteException;
public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException;
public Rect getTaskBounds(int taskId) throws RemoteException;
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 2caec369..7640e75 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -33,7 +33,7 @@
* {@hide}
*/
interface IUiAutomationConnection {
- void connect(IAccessibilityServiceClient client);
+ void connect(IAccessibilityServiceClient client, int flags);
void disconnect();
boolean injectInputEvent(in InputEvent event, boolean sync);
boolean setRotation(int rotation);
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 7a0e7f6..fa0fbd1 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -35,10 +35,16 @@
* 'which' is some combination of:
* FLAG_SET_SYSTEM
* FLAG_SET_LOCK
+ *
+ * A 'null' cropHint rectangle is explicitly permitted as a sentinel for "whatever
+ * the source image's bounding rect is."
+ *
+ * The completion callback's "onWallpaperChanged()" method is invoked when the
+ * new wallpaper content is ready to display.
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
- out Bundle extras, int which);
-
+ in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+
/**
* Set the live wallpaper. This only affects the system wallpaper.
*/
@@ -54,14 +60,14 @@
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
-
+
/**
* If the current system wallpaper is a live wallpaper component, return the
* information about that wallpaper. Otherwise, if it is a static image,
* simply return null.
*/
WallpaperInfo getWallpaperInfo();
-
+
/**
* Clear the system wallpaper.
*/
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 24a3470..9a88f2c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1503,7 +1503,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1561,7 +1561,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -1622,7 +1622,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1682,7 +1682,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1721,7 +1721,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1759,7 +1759,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options);
checkStartActivityResult(result, intent);
@@ -1837,16 +1837,59 @@
* {@link Instrumentation} APIs. Using both APIs at the same time is not
* a mistake by itself but a client has to be aware of the APIs limitations.
* </p>
- * @return The UI automation instance.
+ * @return The UI automation instance. If none exists, a new one is created with no flags set.
*
* @see UiAutomation
*/
public UiAutomation getUiAutomation() {
if (mUiAutomationConnection != null) {
if (mUiAutomation == null) {
+ return getUiAutomation(0);
+ }
+ return mUiAutomation;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the {@link UiAutomation} instance with flags set.
+ * <p>
+ * <strong>Note:</strong> Only one UiAutomation can be obtained. Calling this method
+ * twice with different flags will fail unless the UiAutomation obtained in the first call
+ * is released with {@link UiAutomation#destroy()}.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
+ * work across application boundaries while the APIs exposed by the instrumentation
+ * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
+ * not allow you to inject the event in an app different from the instrumentation
+ * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
+ * will work regardless of the current application.
+ * </p>
+ * <p>
+ * A typical test case should be using either the {@link UiAutomation} or
+ * {@link Instrumentation} APIs. Using both APIs at the same time is not
+ * a mistake by itself but a client has to be aware of the APIs limitations.
+ * </p>
+ *
+ * @param flags The flags to be passed to the UiAutomation, for example
+ * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}.
+ *
+ * @return The UI automation instance.
+ *
+ * @see UiAutomation
+ */
+ public UiAutomation getUiAutomation(int flags) {
+ if (mUiAutomationConnection != null) {
+ if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
mUiAutomationConnection);
- mUiAutomation.connect();
+ mUiAutomation.connect(flags);
+ } else {
+ if (mUiAutomation.getFlags() != flags) {
+ throw new RuntimeException(
+ "Cannot get a UiAutomation with different flags from the existing one");
+ }
}
return mUiAutomation;
}
@@ -1861,8 +1904,8 @@
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
} catch (RuntimeException e) {
- Log.w(TAG, "Exception setting priority of instrumentation thread "
- + Process.myTid(), e);
+ Log.w(TAG, "Exception setting priority of instrumentation thread "
+ + Process.myTid(), e);
}
if (mAutomaticPerformanceSnapshots) {
startPerformanceSnapshot();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0f3aad9..7f037f2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4384,7 +4384,17 @@
view.addView(com.android.internal.R.id.media_actions, button);
}
}
- handleImage(view /* addPaddingToMainColumn */);
+ handleImage(view);
+ // handle the content margin
+ int endMargin;
+ if (mBuilder.mN.mLargeIcon != null) {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin_media);
+ } else {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);
+ }
+ view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
return view;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index edafe59..412b098 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -307,7 +307,7 @@
context.getContentResolver()) : null;
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -332,7 +332,7 @@
context.getContentResolver()) : null;
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -446,7 +446,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -472,7 +472,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -527,7 +527,7 @@
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -570,7 +570,7 @@
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fc1a355..5eed781 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -17,6 +17,7 @@
package android.app;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ISoundTriggerService;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.IDropBoxManagerService;
@@ -61,6 +62,7 @@
import android.media.midi.MidiManager;
import android.media.projection.MediaProjectionManager;
import android.media.session.MediaSessionManager;
+import android.media.soundtrigger.SoundTriggerManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
import android.net.ConnectivityManager;
@@ -708,12 +710,22 @@
public RadioManager createService(ContextImpl ctx) {
return new RadioManager(ctx);
}});
+
registerService(Context.HARDWARE_PROPERTIES_SERVICE, HardwarePropertiesManager.class,
new CachedServiceFetcher<HardwarePropertiesManager>() {
@Override
public HardwarePropertiesManager createService(ContextImpl ctx) {
return new HardwarePropertiesManager();
}});
+
+ registerService(Context.SOUND_TRIGGER_SERVICE, SoundTriggerManager.class,
+ new CachedServiceFetcher<SoundTriggerManager>() {
+ @Override
+ public SoundTriggerManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE);
+ Log.i(TAG, "Creating new instance of SoundTriggerManager object.");
+ return new SoundTriggerManager(ctx, ISoundTriggerService.Stub.asInterface(b));
+ }});
}
/**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index dce2e51..5ec59b4 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -105,6 +105,14 @@
/** Rotation constant: Freeze rotation to 270 degrees . */
public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
+ /**
+ * UiAutomation supresses accessibility services by default. This flag specifies that
+ * existing accessibility services should continue to run, and that new ones may start.
+ * This flag is set when obtaining the UiAutomation from
+ * {@link Instrumentation#getUiAutomation(int)}.
+ */
+ public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 0x00000001;
+
private final Object mLock = new Object();
private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>();
@@ -123,6 +131,10 @@
private boolean mIsConnecting;
+ private boolean mIsDestroyed;
+
+ private int mFlags;
+
/**
* Listener for observing the {@link AccessibilityEvent} stream.
*/
@@ -182,11 +194,22 @@
}
/**
- * Connects this UiAutomation to the accessibility introspection APIs.
+ * Connects this UiAutomation to the accessibility introspection APIs with default flags.
*
* @hide
*/
public void connect() {
+ connect(0);
+ }
+
+ /**
+ * Connects this UiAutomation to the accessibility introspection APIs.
+ *
+ * @param flags Any flags to apply to the automation as it gets connected
+ *
+ * @hide
+ */
+ public void connect(int flags) {
synchronized (mLock) {
throwIfConnectedLocked();
if (mIsConnecting) {
@@ -197,7 +220,8 @@
try {
// Calling out without a lock held.
- mUiAutomationConnection.connect(mClient);
+ mUiAutomationConnection.connect(mClient, flags);
+ mFlags = flags;
} catch (RemoteException re) {
throw new RuntimeException("Error while connecting UiAutomation", re);
}
@@ -227,6 +251,17 @@
}
/**
+ * Get the flags used to connect the service.
+ *
+ * @return The flags used to connect
+ *
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
* Disconnects this UiAutomation from the accessibility introspection APIs.
*
* @hide
@@ -263,6 +298,17 @@
}
/**
+ * Reports if the object has been destroyed
+ *
+ * @return {code true} if the object has been destroyed.
+ *
+ * @hide
+ */
+ public boolean isDestroyed() {
+ return mIsDestroyed;
+ }
+
+ /**
* Sets a callback for observing the stream of {@link AccessibilityEvent}s.
*
* @param listener The callback.
@@ -274,6 +320,15 @@
}
/**
+ * Destroy this UiAutomation. After calling this method, attempting to use the object will
+ * result in errors.
+ */
+ public void destroy() {
+ disconnect();
+ mIsDestroyed = true;
+ }
+
+ /**
* Performs a global action. Such an action can be performed at any moment
* regardless of the current application or user location in that application.
* For example going back, going home, opening recents, etc.
@@ -1033,6 +1088,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ /* do nothing */
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
/* do nothing */
}
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index bd10267..276f774 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -77,7 +77,7 @@
private int mOwningUid;
- public void connect(IAccessibilityServiceClient client) {
+ public void connect(IAccessibilityServiceClient client, int flags) {
if (client == null) {
throw new IllegalArgumentException("Client cannot be null!");
}
@@ -87,7 +87,7 @@
throw new IllegalStateException("Already connected.");
}
mOwningUid = Binder.getCallingUid();
- registerUiTestAutomationServiceLocked(client);
+ registerUiTestAutomationServiceLocked(client, flags);
storeRotationStateLocked();
}
}
@@ -322,7 +322,8 @@
}
}
- private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client) {
+ private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client,
+ int flags) {
IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
@@ -337,7 +338,7 @@
try {
// Calling out with a lock held is fine since if the system
// process is gone the client calling in will be killed.
- manager.registerUiTestAutomationService(mToken, client, info);
+ manager.registerUiTestAutomationService(mToken, client, info, flags);
mClient = client;
} catch (RemoteException re) {
throw new IllegalStateException("Error while registering UiTestAutomationService.", re);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f103576..b0ffd21 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -64,6 +64,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Provides access to the system wallpaper. With WallpaperManager, you can
@@ -770,18 +772,26 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
Resources resources = mContext.getResources();
/* Set the wallpaper to the default values */
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
"res:" + resources.getResourceName(resid),
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), null, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
+ boolean ok = false;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
+ // The 'close()' is the trigger for any server-side image manipulation,
+ // so we must do that before waiting for completion.
+ fos.close();
+ completion.waitForCompletion();
} finally {
+ // Might be redundant but completion shouldn't wait unless the write
+ // succeeded; this is a fallback if it threw past the close+wait.
IoUtils.closeQuietly(fos);
}
}
@@ -876,14 +886,17 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), visibleCropHint, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ fos.close();
+ completion.waitForCompletion();
} finally {
IoUtils.closeQuietly(fos);
}
@@ -990,14 +1003,17 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), visibleCropHint, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
copyStreamToWallpaperFile(bitmapData, fos);
+ fos.close();
+ completion.waitForCompletion();
} finally {
IoUtils.closeQuietly(fos);
}
@@ -1385,4 +1401,28 @@
return null;
}
+
+ // Private completion callback for setWallpaper() synchronization
+ private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
+ final CountDownLatch mLatch;
+
+ public WallpaperSetCompletion() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ public void waitForCompletion() {
+ try {
+ mLatch.await(30, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // This might be legit: the crop may take a very long time. Don't sweat
+ // it in that case; we are okay with display lagging behind in order to
+ // keep the caller from locking up indeterminately.
+ }
+ }
+
+ @Override
+ public void onWallpaperChanged() throws RemoteException {
+ mLatch.countDown();
+ }
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1c1526f..c79c407 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -30,6 +30,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -2770,6 +2771,45 @@
}
/**
+ * Called by a device owner to set whether all users created on the device should be ephemeral.
+ *
+ * <p>The system user is exempt from this policy - it is never ephemeral.
+ *
+ * <p>The calling device admin must be the device owner. If it is not, a security exception will
+ * be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param forceEphemeralUsers If true, all the existing users will be deleted and all
+ * subsequently created users will be ephemeral.
+ * @hide
+ */
+ public void setForceEphemeralUsers(
+ @NonNull ComponentName admin, boolean forceEphemeralUsers) {
+ if (mService != null) {
+ try {
+ mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * @return true if all users are created ephemeral.
+ * @hide
+ */
+ public boolean getForceEphemeralUsers(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getForceEphemeralUsers(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Called by an application that is administering the device to disable keyguard customizations,
* such as widgets. After setting this, keyguard features will be disabled according to the
* provided feature list.
@@ -2934,6 +2974,34 @@
}
/**
+ * Should be called when keyguard has been dismissed.
+ * @hide
+ */
+ public void reportKeyguardDismissed() {
+ if (mService != null) {
+ try {
+ mService.reportKeyguardDismissed();
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Should be called when keyguard view has been shown to the user.
+ * @hide
+ */
+ public void reportKeyguardSecured() {
+ if (mService != null) {
+ try {
+ mService.reportKeyguardSecured();
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
* @hide
* Sets the given package as the device owner.
* Same as {@link #setDeviceOwner(ComponentName, String)} but without setting a device owner name.
@@ -3205,15 +3273,14 @@
}
/**
- * @hide
* Clears the active profile owner and removes all user restrictions. The caller must
* be from the same package as the active profile owner for this user, otherwise a
* SecurityException will be thrown.
*
+ * <p>This doesn't work for managed profile owners.
+ *
* @param admin The component to remove as the profile owner.
- * @return
*/
- @SystemApi
public void clearProfileOwner(@NonNull ComponentName admin) {
if (mService != null) {
try {
@@ -3279,6 +3346,10 @@
* <p>If the device owner information contains only whitespaces then the message on the lock
* screen will be blank and the user will not be allowed to change it.
*
+ * <p>If the device owner information needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user
* owner info.
@@ -5144,6 +5215,10 @@
* for support."
* If the message is longer than 200 characters it may be truncated.
*
+ * <p>If the short support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setLongSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5183,6 +5258,10 @@
* Called by a device admin to set the long support message. This will
* be displayed to the user in the device administators settings screen.
*
+ * <p>If the long support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setShortSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5280,6 +5359,22 @@
}
/**
+ * Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent
+ * profile.
+ *
+ * @hide
+ */
+ public DevicePolicyManager getParentProfileInstance(UserInfo uInfo) {
+ mContext.checkSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ if (!uInfo.isManagedProfile()) {
+ throw new SecurityException("The user " + uInfo.id
+ + " does not have a parent profile.");
+ }
+ return new DevicePolicyManager(mContext, true);
+ }
+
+ /**
* Called by a profile owner of a managed profile to set the color used for customization.
* This color is used as background color of the confirm credentials screen for that user.
* The default color is {@link android.graphics.Color#GRAY}.
@@ -5331,6 +5426,58 @@
}
/**
+ * Called by a profile owner of a managed profile to set the name of the organization under
+ * management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param title The organization name or {@code null} to clear a previously set name.
+ */
+ public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+ try {
+ mService.setOrganizationName(admin, title);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ }
+ }
+
+ /**
+ * Called by a profile owner of a managed profile to retrieve the name of the organization
+ * under management.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The organization name or {@code null} if none is set.
+ */
+ public String getOrganizationName(@NonNull ComponentName admin) {
+ try {
+ return mService.getOrganizationName(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the default title message used in the confirm credentials screen for a given user.
+ *
+ * @param userHandle The user id of the user we're interested in.
+ * @return The organization name or {@code null} if none is set.
+ *
+ * @hide
+ */
+ public String getOrganizationNameForUser(int userHandle) {
+ try {
+ return mService.getOrganizationNameForUser(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
* @return the {@link UserProvisioningState} for the current user - for unmanaged users will
* return {@link #STATE_USER_UNMANAGED}
* @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a80ed9b..37d13e5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -116,6 +116,9 @@
void reportFailedPasswordAttempt(int userHandle);
void reportSuccessfulPasswordAttempt(int userHandle);
+ void reportKeyguardDismissed();
+ void reportKeyguardSecured();
+
boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
String getDeviceOwnerName();
@@ -230,6 +233,9 @@
void setAutoTimeRequired(in ComponentName who, boolean required);
boolean getAutoTimeRequired();
+ void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
+ boolean getForceEphemeralUsers(in ComponentName who);
+
boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
void setUserIcon(in ComponentName admin, in Bitmap icon);
@@ -270,6 +276,10 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
+ void setOrganizationName(in ComponentName admin, in String title);
+ String getOrganizationName(in ComponentName admin);
+ String getOrganizationNameForUser(int userHandle);
+
int getUserProvisioningState();
void setUserProvisioningState(int state, int userHandle);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index ff62b7c..2268400 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -538,7 +538,7 @@
@Override
public void onResult(String currentPackage, int status) {
mHandler.sendMessage(
- mHandler.obtainMessage(MSG_FINISHED, status, 0, currentPackage));
+ mHandler.obtainMessage(MSG_RESULT, status, 0, currentPackage));
}
@Override
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index d263646..5622207 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -151,21 +151,6 @@
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
/**
- * Combined usage across all metering states.
- */
- public static final int METERING_ALL = -1;
-
- /**
- * Usage not accounted for in any other metering state.
- */
- public static final int METERING_DEFAULT = 0x1;
-
- /**
- * Metered usage.
- */
- public static final int METERING_METERED = 0x2;
-
- /**
* Combined usage across all roaming states.
*/
public static final int ROAMING_ALL = -1;
@@ -182,7 +167,6 @@
private int mUid;
private int mState;
- private int mMetering;
private int mRoaming;
private long mBeginTimeStamp;
private long mEndTimeStamp;
@@ -247,18 +231,6 @@
}
/**
- * Metering state. One of the following values:<p/>
- * <ul>
- * <li>{@link #METERING_ALL}</li>
- * <li>{@link #METERING_DEFAULT}</li>
- * <li>{@link #METERING_METERED}</li>
- * </ul>
- */
- public int getMetering() {
- return mMetering;
- }
-
- /**
* Roaming state. One of the following values:<p/>
* <ul>
* <li>{@link #ROAMING_ALL}</li>
@@ -463,8 +435,6 @@
private void fillBucketFromSummaryEntry(Bucket bucketOut) {
bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
- // TODO: Implement metering tracking.
- bucketOut.mMetering = Bucket.METERING_ALL;
bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
bucketOut.mBeginTimeStamp = mStartTimeStamp;
bucketOut.mEndTimeStamp = mEndTimeStamp;
@@ -512,7 +482,6 @@
mRecycledHistoryEntry);
bucketOut.mUid = Bucket.convertUid(getUid());
bucketOut.mState = Bucket.STATE_ALL;
- bucketOut.mMetering = Bucket.METERING_ALL;
bucketOut.mRoaming = Bucket.ROAMING_ALL;
bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index e8373a1..1a9bf4e 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -52,10 +52,12 @@
* {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
* {@link NetworkStats.Bucket#ROAMING_ALL}.
* <p />
- * <b>NOTE:</b> Accessing stats for apps other than the calling app 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.
+ * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
+ * calling app 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.
+ * <p />
* 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 and carrier-
* privileged apps likewise get access to usage data for all users on the device.
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0fce4e2..a88aa3125 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -165,14 +165,18 @@
mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
}
- if (right.mEndTimeStamp > mEndTimeStamp) {
+ if (right.mBeginTimeStamp > mBeginTimeStamp) {
+ // The incoming UsageStat begins after this one, so use its last time used fields
+ // as the source of truth.
+ // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+ // regards to their mEndTimeStamp.
mLastEvent = right.mLastEvent;
- mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
mBeginIdleTime = right.mBeginIdleTime;
mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+ mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
mLaunchCount += right.mLaunchCount;
}
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
index 87dc1d8..8d8d2f5 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/auditing/SecurityLog.java
@@ -34,7 +34,8 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
- TAG_APP_PROCESS_START, TAG_DEVICE_UNLOCK_ATTEMPT, TAG_DEVICE_LOCKED})
+ TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+ TAG_KEYGUARD_SECURED})
public @interface SECURITY_LOG_TAG {}
/**
@@ -68,21 +69,24 @@
* seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
*/
public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
-
/**
- * Indicate that there has been an attempt to unlock the device. The log entry contains the
- * following information about the attempt in order, accessible via
- * {@link SecurityEvent#getData()}}: unlock result (integer, 1 for successful unlock, 0 for
- * unsuccessful), unlock method (String)
+ * Indicate that keyguard is being dismissed.
+ * There is no extra payload in the log event.
*/
- public static final int TAG_DEVICE_UNLOCK_ATTEMPT =
- SecurityLogTags.SECURITY_DEVICE_UNLOCK_ATTEMPT;
-
+ public static final int TAG_KEYGUARD_DISMISSED =
+ SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
+ /**
+ * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
+ * contains the attempt result (integer, 1 for successful, 0 for unsuccessful), accessible via
+ * {@link SecurityEvent#getData()}}
+ */
+ public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
+ SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
/**
* Indicate that the device has been locked, either by user or by timeout.
+ * There is no extra payload in the log event.
*/
- public static final int TAG_DEVICE_LOCKED = SecurityLogTags.SECURITY_DEVICE_LOCKED;
-
+ public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
/**
* Returns if device logging is enabled. Log producers should only write new logs if this is
@@ -128,7 +132,9 @@
* Returns the tag of this log entry, which specifies entry's semantics.
* Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
* {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
- * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START}.
+ * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
+ * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
+ * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
*/
public @SECURITY_LOG_TAG int getTag() {
return mEvent.getTag();
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags
index 455acff..cf85894 100644
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ b/core/java/android/auditing/SecurityLogTags.logtags
@@ -3,9 +3,10 @@
option java_package android.auditing
210001 security_adb_shell_interactive
-210002 security_adb_shell_command (command|3)
-210003 security_adb_sync_recv (path|3)
-210004 security_adb_sync_send (path|3)
-210005 security_app_process_start (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
-210006 security_device_unlock_attempt (success|1),(method|3)
-210007 security_device_locked
\ No newline at end of file
+210002 security_adb_shell_command (command|3)
+210003 security_adb_sync_recv (path|3)
+210004 security_adb_sync_send (path|3)
+210005 security_app_process_start (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
+210006 security_keyguard_dismissed
+210007 security_keyguard_dismiss_auth_attempt (success|1)
+210008 security_keyguard_secured
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 3660be7..6b5f77f 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -23,6 +23,7 @@
import android.bluetooth.le.ScanSettings;
import android.bluetooth.le.ResultStorageDescriptor;
import android.os.ParcelUuid;
+import android.os.WorkSource;
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothGattServerCallback;
@@ -35,8 +36,8 @@
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
- in List<ScanFilter> filters,
- in List scanStorages, in String callingPackage);
+ in List<ScanFilter> filters, in WorkSource workSource, in List scanStorages,
+ in String callingPackage);
void stopScan(in int appIf, in boolean isServer);
void flushPendingBatchResults(in int appIf, in boolean isServer);
void startMultiAdvertising(in int appIf,
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 2ba87744..03449cc 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -29,6 +29,7 @@
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.util.Log;
import java.util.ArrayList;
@@ -89,9 +90,6 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public void startScan(final ScanCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback is null");
- }
startScan(null, new ScanSettings.Builder().build(), callback);
}
@@ -112,14 +110,53 @@
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
- startScan(filters, settings, callback, null);
+ startScan(filters, settings, null, callback, null);
+ }
+
+ /**
+ * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to
+ * specify on behalf of which application(s) the work is being done.
+ *
+ * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
+ * the scan.
+ * @param callback Callback used to deliver scan results.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
+ public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
+ startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
+ }
+
+ /**
+ * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but
+ * allows the caller to specify on behalf of which application(s) the work is being done.
+ *
+ * @param filters {@link ScanFilter}s for finding exact BLE devices.
+ * @param settings Settings for the scan.
+ * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
+ * the scan.
+ * @param callback Callback used to deliver scan results.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
+ public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
+ final WorkSource workSource, final ScanCallback callback) {
+ startScan(filters, settings, workSource, callback, null);
}
private void startScan(List<ScanFilter> filters, ScanSettings settings,
- final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) {
+ final WorkSource workSource, final ScanCallback callback,
+ List<List<ResultStorageDescriptor>> resultStorages) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (settings == null || callback == null) {
- throw new IllegalArgumentException("settings or callback is null");
+ if (callback == null) {
+ throw new IllegalArgumentException("callback is null");
+ }
+ if (settings == null) {
+ throw new IllegalArgumentException("settings is null");
}
synchronized (mLeScanClients) {
if (mLeScanClients.containsKey(callback)) {
@@ -152,7 +189,7 @@
return;
}
BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
- settings, callback, resultStorages);
+ settings, workSource, callback, resultStorages);
wrapper.startRegisteration();
}
}
@@ -215,7 +252,7 @@
scanFilters.add(filter.getFilter());
scanStorages.add(filter.getStorageDescriptors());
}
- startScan(scanFilters, settings, callback, scanStorages);
+ startScan(scanFilters, settings, null, callback, scanStorages);
}
/**
@@ -235,6 +272,7 @@
private final ScanCallback mScanCallback;
private final List<ScanFilter> mFilters;
+ private final WorkSource mWorkSource;
private ScanSettings mSettings;
private IBluetoothGatt mBluetoothGatt;
private List<List<ResultStorageDescriptor>> mResultStorages;
@@ -246,10 +284,12 @@
public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
List<ScanFilter> filters, ScanSettings settings,
- ScanCallback scanCallback, List<List<ResultStorageDescriptor>> resultStorages) {
+ WorkSource workSource, ScanCallback scanCallback,
+ List<List<ResultStorageDescriptor>> resultStorages) {
mBluetoothGatt = bluetoothGatt;
mFilters = filters;
mSettings = settings;
+ mWorkSource = workSource;
mScanCallback = scanCallback;
mClientIf = 0;
mResultStorages = resultStorages;
@@ -322,7 +362,9 @@
mClientIf = clientIf;
try {
mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters,
- mResultStorages, ActivityThread.currentOpPackageName());
+ mWorkSource, mResultStorages,
+ ActivityThread.currentOpPackageName());
+
} catch (RemoteException e) {
Log.e(TAG, "fail to start le scan: " + e);
mClientIf = -1;
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 2260d7e..10e6fb2 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -522,7 +522,7 @@
IActivityManager am = ActivityManagerNative.getDefault();
IBinder binder = null;
try {
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6dfefac..0ec58ea 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -823,14 +823,14 @@
*
* @hide
*/
- public void prepareToLeaveProcess() {
+ public void prepareToLeaveProcess(boolean leavingPackage) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
- item.mIntent.prepareToLeaveProcess();
+ item.mIntent.prepareToLeaveProcess(leavingPackage);
}
- if (item.mUri != null && StrictMode.vmFileUriExposureEnabled()) {
+ if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
}
}
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 5653cad..e67da2b 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -118,7 +118,7 @@
public void setPrimaryClip(ClipData clip) {
try {
if (clip != null) {
- clip.prepareToLeaveProcess();
+ clip.prepareToLeaveProcess(true);
}
getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 27cdd50..3142b40 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2613,6 +2613,7 @@
MIDI_SERVICE,
RADIO_SERVICE,
HARDWARE_PROPERTIES_SERVICE,
+ //@hide: SOUND_TRIGGER_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3195,6 +3196,16 @@
public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
/**
+ * Use with {@link #getSystemService} to access the
+ * {@link com.android.server.voiceinteraction.SoundTriggerService}.
+ *
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String SOUND_TRIGGER_SERVICE = "soundtrigger";
+
+
+ /**
* Use with {@link #getSystemService} to retrieve an
* {@link android.app.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 06da4955..ee469da 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1575,6 +1575,14 @@
= "android.intent.extra.UNINSTALL_ALL_USERS";
/**
+ * Specified when the uninstall confirmation dialog is not required to be shown.
+ * Use with {@link #ACTION_UNINSTALL_PACKAGE}
+ * @hide
+ */
+ public static final String EXTRA_SKIP_UNINSTALL_CONFIRMATION =
+ "android.intent.extra.SKIP_UNINSTALL_CONFIRMATION";
+
+ /**
* A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
* describing the last run version of the platform that was setup.
* @hide
@@ -2618,8 +2626,7 @@
* turned off</li>
* </ul>
*
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
+ * <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
@@ -3210,6 +3217,18 @@
public static final String
ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
+ /**
+ * Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
+ * exisiting sensor being disconnected.
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.</p>
+ *
+ * {@hide}
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String
+ ACTION_DYNAMIC_SENSOR_CHANGED = "android.intent.action.DYNAMIC_SENSOR_CHANGED";
+
/** {@hide} */
public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
@@ -5698,6 +5717,9 @@
case "--receiver-replace-pending":
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
break;
+ case "--receiver-foreground":
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ break;
case "--selector":
intent.setDataAndType(data, type);
intent = new Intent();
@@ -5807,6 +5829,7 @@
" [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]",
" (mutiple extras passed as List<String>; to embed a comma into a string,",
" escape it using \"\\,\")",
+ " [--f <FLAG>]",
" [--grant-read-uri-permission] [--grant-write-uri-permission]",
" [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]",
" [--debug-log-resolution] [--exclude-stopped-packages]",
@@ -5820,6 +5843,7 @@
" [--activity-single-top] [--activity-clear-task]",
" [--activity-task-on-home]",
" [--receiver-registered-only] [--receiver-replace-pending]",
+ " [--receiver-foreground]",
" [--selector]",
" [<URI> | <PACKAGE> | <COMPONENT>]"
};
@@ -8888,23 +8912,46 @@
*
* @hide
*/
- public void prepareToLeaveProcess() {
+ public void prepareToLeaveProcess(Context context) {
+ final boolean leavingPackage = (mComponent == null)
+ || !Objects.equals(mComponent.getPackageName(), context.getPackageName());
+ prepareToLeaveProcess(leavingPackage);
+ }
+
+ /**
+ * Prepare this {@link Intent} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess(boolean leavingPackage) {
setAllowFds(false);
if (mSelector != null) {
- mSelector.prepareToLeaveProcess();
+ mSelector.prepareToLeaveProcess(leavingPackage);
}
if (mClipData != null) {
- mClipData.prepareToLeaveProcess();
+ mClipData.prepareToLeaveProcess(leavingPackage);
}
- if (mData != null && StrictMode.vmFileUriExposureEnabled()) {
- // There are several ACTION_MEDIA_* broadcasts that send file://
- // Uris, so only check common actions.
- if (ACTION_VIEW.equals(mAction) ||
- ACTION_EDIT.equals(mAction) ||
- ACTION_ATTACH_DATA.equals(mAction)) {
- mData.checkFileUriExposed("Intent.getData()");
+ if (mData != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
+ switch (mAction) {
+ case ACTION_MEDIA_REMOVED:
+ case ACTION_MEDIA_UNMOUNTED:
+ case ACTION_MEDIA_CHECKING:
+ case ACTION_MEDIA_NOFS:
+ case ACTION_MEDIA_MOUNTED:
+ case ACTION_MEDIA_SHARED:
+ case ACTION_MEDIA_UNSHARED:
+ case ACTION_MEDIA_BAD_REMOVAL:
+ case ACTION_MEDIA_UNMOUNTABLE:
+ case ACTION_MEDIA_EJECT:
+ case ACTION_MEDIA_SCANNER_STARTED:
+ case ACTION_MEDIA_SCANNER_FINISHED:
+ case ACTION_MEDIA_SCANNER_SCAN_FILE:
+ // Ignore legacy actions
+ break;
+ default:
+ mData.checkFileUriExposed("Intent.getData()");
}
}
}
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 1d16516..7f9e176 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -30,8 +30,7 @@
* when they are committed to storage. Objects that are returned from the
* various <code>get</code> methods must be treated as immutable by the application.
*
- * <p><em>Note: currently this class does not support use across multiple
- * processes. This will be added later.</em>
+ * <p><em>Note: This class does not support use across multiple processes.</em>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index dedf07f5..10b8a30 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -156,6 +156,35 @@
public String targetActivity;
/**
+ * Activity can not be resized and always occupies the fullscreen area with all windows fully
+ * visible.
+ * @hide
+ */
+ public static final int RESIZE_MODE_UNRESIZEABLE = 0;
+ /**
+ * Activity can not be resized and always occupies the fullscreen area with all windows cropped
+ * to either the task or stack bounds.
+ * @hide
+ */
+ public static final int RESIZE_MODE_CROP_WINDOWS = 1;
+ /**
+ * Activity is resizeable.
+ * @hide
+ */
+ public static final int RESIZE_MODE_RESIZEABLE = 2;
+ /**
+ * Activity is resizeable and supported picture-in-picture mode.
+ * @hide
+ */
+ public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
+ /**
+ * Value indicating if the resizing mode the activity supports.
+ * See {@link android.R.attr#resizeableActivity}.
+ * @hide
+ */
+ public int resizeMode;
+
+ /**
* Bit in {@link #flags} indicating whether this activity is able to
* run in multiple processes. If
* true, the system may instantiate it in the some process as the
@@ -283,20 +312,6 @@
public static final int FLAG_ENABLE_VR_MODE = 0x8000;
/**
- * Bit in {@link #flags} indicating if the activity is resizeable to any dimension.
- * See {@link android.R.attr#resizeableActivity}.
- * @hide
- */
- public static final int FLAG_RESIZEABLE = 0x10000;
-
- /**
- * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of
- * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}.
- * @hide
- */
- public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000;
-
- /**
* Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
* in a task/stack whose activities are normally not focusable.
* See android.R.attr#alwaysFocusable.
@@ -746,6 +761,7 @@
maxRecents = orig.maxRecents;
lockTaskLaunchMode = orig.lockTaskLaunchMode;
layout = orig.layout;
+ resizeMode = orig.resizeMode;
}
/**
@@ -768,6 +784,27 @@
}
}
+ /** @hide */
+ public static boolean isResizeableMode(int mode) {
+ return mode == RESIZE_MODE_RESIZEABLE || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ }
+
+ /** @hide */
+ public static String resizeModeToString(int mode) {
+ switch (mode) {
+ case RESIZE_MODE_UNRESIZEABLE:
+ return "RESIZE_MODE_UNRESIZEABLE";
+ case RESIZE_MODE_CROP_WINDOWS:
+ return "RESIZE_MODE_CROP_WINDOWS";
+ case RESIZE_MODE_RESIZEABLE:
+ return "RESIZE_MODE_RESIZEABLE";
+ case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
+ return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE";
+ default:
+ return "unknown=" + mode;
+ }
+ }
+
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
@@ -806,6 +843,7 @@
+ layout.widthFraction + ", " + layout.height + "|"
+ layout.heightFraction + ", " + layout.gravity);
}
+ pw.println(prefix + "resizeMode=" + resizeModeToString(resizeMode));
super.dumpBack(pw, prefix, flags);
}
@@ -847,6 +885,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeInt(resizeMode);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -879,6 +918,7 @@
if (source.readInt() == 1) {
layout = new Layout(source);
}
+ resizeMode = source.readInt();
}
public static final class Layout {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 476dc46..3a94bf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2017,6 +2017,11 @@
public static final String FEATURE_SECURELY_REMOVES_USERS
= "android.software.securely_removes_users";
+ /** {@hide} */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_FILE_BASED_ENCRYPTION
+ = "android.software.file_based_encryption";
+
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has a full implementation of the android.webkit.* APIs. Devices
@@ -3627,7 +3632,7 @@
* {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
* {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
* to modify the data returned.
- * @param userId The userId of the user being queried.
+ * @param userHandle UserHandle of the user being queried.
*
* @return Returns a List of ResolveInfo objects containing one entry for each
* matching receiver, ordered from best to worst. If there are no matching
@@ -3648,9 +3653,19 @@
*
* @hide
*/
+ @SystemApi
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ @ResolveInfoFlags int flags, UserHandle userHandle) {
+ return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
+ }
+
+ /**
+ * @hide
+ */
public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
+
/** {@hide} */
@Deprecated
public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a6fec9f..44cd003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -16,15 +16,12 @@
package android.content.pm;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import android.app.ActivityManager;
import android.content.ComponentName;
@@ -55,15 +52,6 @@
import android.util.jar.StrictJarFile;
import android.view.Gravity;
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -87,6 +75,25 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.ZipEntry;
+import libcore.io.IoUtils;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
/**
* Parser for package files (APKs) on disk. This supports apps packaged either
* as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
@@ -3219,24 +3226,29 @@
a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
}
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
- a.info.flags |= ActivityInfo.FLAG_RESIZEABLE;
+ a.info.screenOrientation = sa.getInt(
+ R.styleable.AndroidManifestActivity_screenOrientation,
+ SCREEN_ORIENTATION_UNSPECIFIED);
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
- false)) {
- a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, true)) {
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+ false)) {
+ a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ } else {
+ a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+ }
}
+ } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
+ && (a.info.flags & FLAG_IMMERSIVE) == 0) {
+ a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
- a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+ a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
}
- a.info.screenOrientation = sa.getInt(
- R.styleable.AndroidManifestActivity_screenOrientation,
- ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-
a.info.lockTaskLaunchMode =
sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
@@ -3478,6 +3490,8 @@
info.parentActivityName = target.info.parentActivityName;
info.maxRecents = target.info.maxRecents;
info.layout = target.info.layout;
+ info.resizeMode = target.info.resizeMode;
+ info.encryptionAware = target.info.encryptionAware;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 19921b5..9e1b312 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -69,7 +69,7 @@
* href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
* List Resource</a>.</p>
*/
-public class ColorStateList implements Parcelable {
+public class ColorStateList extends ComplexColor implements Parcelable {
private static final String TAG = "ColorStateList";
private static final int DEFAULT_COLOR = Color.RED;
@@ -209,7 +209,7 @@
* @return A new color state list for the current tag.
*/
@NonNull
- private static ColorStateList createFromXmlInner(@NonNull Resources r,
+ static ColorStateList createFromXmlInner(@NonNull Resources r,
@NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
final String name = parser.getName();
@@ -340,6 +340,7 @@
* @return whether a theme can be applied to this color state list
* @hide only for resource preloading
*/
+ @Override
public boolean canApplyTheme() {
return mThemeAttrs != null;
}
@@ -419,6 +420,7 @@
* attributes
* @hide only for resource preloading
*/
+ @Override
public ColorStateList obtainForTheme(Theme t) {
if (t == null || !canApplyTheme()) {
return this;
@@ -460,6 +462,7 @@
* otherwise.
* @see #getColorForState(int[], int)
*/
+ @Override
public boolean isStateful() {
return mStateSpecs.length > 1;
}
@@ -602,14 +605,14 @@
* @return a factory that can create new instances of this ColorStateList
* @hide only for resource preloading
*/
- public ConstantState<ColorStateList> getConstantState() {
+ public ConstantState<ComplexColor> getConstantState() {
if (mFactory == null) {
mFactory = new ColorStateListFactory(this);
}
return mFactory;
}
- private static class ColorStateListFactory extends ConstantState<ColorStateList> {
+ private static class ColorStateListFactory extends ConstantState<ComplexColor> {
private final ColorStateList mSrc;
public ColorStateListFactory(ColorStateList src) {
@@ -628,7 +631,7 @@
@Override
public ColorStateList newInstance(Resources res, Theme theme) {
- return mSrc.obtainForTheme(theme);
+ return (ColorStateList) mSrc.obtainForTheme(theme);
}
}
diff --git a/core/java/android/content/res/ComplexColor.java b/core/java/android/content/res/ComplexColor.java
new file mode 100644
index 0000000..d96ec62
--- /dev/null
+++ b/core/java/android/content/res/ComplexColor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorInt;
+import android.content.res.Resources.Theme;
+import android.graphics.Color;
+
+/**
+ * Defines an abstract class for the complex color information, like
+ * {@link android.content.res.ColorStateList} or {@link android.content.res.GradientColor}
+ */
+public abstract class ComplexColor {
+ /**
+ * @return {@code true} if this ComplexColor changes color based on state, {@code false}
+ * otherwise.
+ */
+ public boolean isStateful() { return false; }
+
+ /**
+ * @return the default color.
+ */
+ @ColorInt
+ public abstract int getDefaultColor();
+
+ /**
+ * @hide only for resource preloading
+ *
+ */
+ public abstract ConstantState<ComplexColor> getConstantState();
+
+ /**
+ * @hide only for resource preloading
+ */
+ public abstract boolean canApplyTheme();
+
+ /**
+ * @hide only for resource preloading
+ */
+ public abstract ComplexColor obtainForTheme(Theme t);
+}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
new file mode 100644
index 0000000..98ef2ea
--- /dev/null
+++ b/core/java/android/content/res/GradientColor.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+
+import com.android.internal.R;
+import com.android.internal.util.GrowingArrayUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.IOException;
+
+
+public class GradientColor extends ComplexColor {
+ private static final String TAG = "GradientColor";
+
+ private static final boolean DBG_GRADIENT = false;
+
+ /** Lazily-created factory for this GradientColor. */
+ private GradientColorFactory mFactory;
+
+ private int mChangingConfigurations;
+ private int mDefaultColor;
+
+ // After parsing all the attributes from XML, this shader is the ultimate result containing
+ // all the XML information.
+ private Shader mShader = null;
+
+ // Below are the attributes at the root element <gradient>
+ private int mGradientType = GradientDrawable.LINEAR_GRADIENT;
+
+ private float mCenterX = 0f;
+ private float mCenterY = 0f;
+
+ private float mStartX = 0f;
+ private float mStartY = 0f;
+ private float mEndX = 0f;
+ private float mEndY = 0f;
+
+ private int mStartColor = 0;
+ private int mCenterColor = 0;
+ private int mEndColor = 0;
+ private boolean mHasCenterColor = false;
+
+ private float mGradientRadius = 0f;
+
+ // Below are the attributes for the <item> element.
+ private int[] mItemColors;
+ private float[] mItemOffsets;
+
+ // Theme attributes for the root and item elements.
+ private int[] mThemeAttrs;
+ private int[][] mItemsThemeAttrs;
+
+ private GradientColor() {
+ }
+
+ private GradientColor(GradientColor copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mDefaultColor = copy.mDefaultColor;
+ mShader = copy.mShader;
+ mGradientType = copy.mGradientType;
+ mCenterX = copy.mCenterX;
+ mCenterY = copy.mCenterY;
+ mStartX = copy.mStartX;
+ mStartY = copy.mStartY;
+ mEndX = copy.mEndX;
+ mEndY = copy.mEndY;
+ mStartColor = copy.mStartColor;
+ mCenterColor = copy.mCenterColor;
+ mEndColor = copy.mEndColor;
+ mHasCenterColor = copy.mHasCenterColor;
+ mGradientRadius = copy.mGradientRadius;
+
+ if (copy.mItemColors != null) {
+ mItemColors = copy.mItemColors.clone();
+ }
+ if (copy.mItemOffsets != null) {
+ mItemOffsets = copy.mItemOffsets.clone();
+ }
+
+ if (copy.mThemeAttrs != null) {
+ mThemeAttrs = copy.mThemeAttrs.clone();
+ }
+ if (copy.mItemsThemeAttrs != null) {
+ mItemsThemeAttrs = copy.mItemsThemeAttrs.clone();
+ }
+ }
+ }
+
+ /**
+ * Update the root level's attributes, either for inflate or applyTheme.
+ */
+ private void updateRootElementState(TypedArray a) {
+ // Extract the theme attributes, if any.
+ mThemeAttrs = a.extractThemeAttrs();
+
+ mStartX = a.getFloat(
+ R.styleable.GradientColor_startX, mStartX);
+ mStartY = a.getFloat(
+ R.styleable.GradientColor_startY, mStartY);
+ mEndX = a.getFloat(
+ R.styleable.GradientColor_endX, mEndX);
+ mEndY = a.getFloat(
+ R.styleable.GradientColor_endY, mEndY);
+
+ mCenterX = a.getFloat(
+ R.styleable.GradientColor_centerX, mCenterX);
+ mCenterY = a.getFloat(
+ R.styleable.GradientColor_centerY, mCenterY);
+
+ mGradientType = a.getInt(
+ R.styleable.GradientColor_type, mGradientType);
+
+ mStartColor = a.getColor(
+ R.styleable.GradientColor_startColor, mStartColor);
+ mHasCenterColor |= a.hasValue(
+ R.styleable.GradientColor_centerColor);
+ mCenterColor = a.getColor(
+ R.styleable.GradientColor_centerColor, mCenterColor);
+ mEndColor = a.getColor(
+ R.styleable.GradientColor_endColor, mEndColor);
+
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "hasCenterColor is " + mHasCenterColor);
+ if (mHasCenterColor) {
+ Log.v(TAG, "centerColor:" + mCenterColor);
+ }
+ Log.v(TAG, "startColor: " + mStartColor);
+ Log.v(TAG, "endColor: " + mEndColor);
+ }
+
+ mGradientRadius = a.getFloat(R.styleable.GradientColor_gradientRadius,
+ mGradientRadius);
+ }
+
+ /**
+ * Check if the XML content is valid.
+ *
+ * @throws XmlPullParserException if errors were found.
+ */
+ private void validateXmlContent() throws XmlPullParserException {
+ if (mGradientRadius <= 0
+ && mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+ throw new XmlPullParserException(
+ "<gradient> tag requires 'gradientRadius' "
+ + "attribute with radial type");
+ }
+ }
+
+ /**
+ * The shader information will be applied to the native VectorDrawable's path.
+ * @hide
+ */
+ public Shader getShader() {
+ return mShader;
+ }
+
+ /**
+ * A public method to create GradientColor from a XML resource.
+ */
+ public static GradientColor createFromXml(Resources r, XmlResourceParser parser, Theme theme)
+ throws XmlPullParserException, IOException {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Seek parser to start tag.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ return createFromXmlInner(r, parser, attrs, theme);
+ }
+
+ /**
+ * Create from inside an XML document. Called on a parser positioned at a
+ * tag in an XML document, tries to create a GradientColor from that tag.
+ *
+ * @return A new GradientColor for the current tag.
+ * @throws XmlPullParserException if the current tag is not <gradient>
+ */
+ @NonNull
+ static GradientColor createFromXmlInner(@NonNull Resources r,
+ @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final String name = parser.getName();
+ if (!name.equals("gradient")) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription() + ": invalid gradient color tag " + name);
+ }
+
+ final GradientColor gradientColor = new GradientColor();
+ gradientColor.inflate(r, parser, attrs, theme);
+ return gradientColor;
+ }
+
+ /**
+ * Fill in this object based on the contents of an XML "gradient" element.
+ */
+ private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final TypedArray a = Resources.obtainAttributes(r, theme, attrs, R.styleable.GradientColor);
+ updateRootElementState(a);
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+
+ // Check correctness and throw exception if errors found.
+ validateXmlContent();
+
+ inflateChildElements(r, parser, attrs, theme);
+
+ onColorsChange();
+ }
+
+ /**
+ * Inflates child elements "item"s for each color stop.
+ *
+ * Note that at root level, we need to save ThemeAttrs for theme applied later.
+ * Here similarly, at each child item, we need to save the theme's attributes, and apply theme
+ * later as applyItemsAttrsTheme().
+ */
+ private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @NonNull Theme theme)
+ throws XmlPullParserException, IOException {
+ final int innerDepth = parser.getDepth() + 1;
+ int type;
+ int depth;
+
+ // Pre-allocate the array with some size, for better performance.
+ float[] offsetList = new float[20];
+ int[] colorList = new int[offsetList.length];
+ int[][] themeAttrsList = new int[offsetList.length][];
+
+ int listSize = 0;
+ boolean hasUnresolvedAttrs = false;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
+ R.styleable.GradientColorItem);
+ boolean hasColor = a.hasValue(R.styleable.GradientColorItem_color);
+ boolean hasOffset = a.hasValue(R.styleable.GradientColorItem_offset);
+ if (!hasColor || !hasOffset) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'color' attribute and a 'offset' "
+ + "attribute!");
+ }
+
+ final int[] themeAttrs = a.extractThemeAttrs();
+ int color = a.getColor(R.styleable.GradientColorItem_color, 0);
+ float offset = a.getFloat(R.styleable.GradientColorItem_offset, 0);
+
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "new item color " + color + " " + Integer.toHexString(color));
+ Log.v(TAG, "offset" + offset);
+ }
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+
+ if (themeAttrs != null) {
+ hasUnresolvedAttrs = true;
+ }
+
+ colorList = GrowingArrayUtils.append(colorList, listSize, color);
+ offsetList = GrowingArrayUtils.append(offsetList, listSize, offset);
+ themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
+ listSize++;
+ }
+ if (listSize > 0) {
+ if (hasUnresolvedAttrs) {
+ mItemsThemeAttrs = new int[listSize][];
+ System.arraycopy(themeAttrsList, 0, mItemsThemeAttrs, 0, listSize);
+ } else {
+ mItemsThemeAttrs = null;
+ }
+
+ mItemColors = new int[listSize];
+ mItemOffsets = new float[listSize];
+ System.arraycopy(colorList, 0, mItemColors, 0, listSize);
+ System.arraycopy(offsetList, 0, mItemOffsets, 0, listSize);
+ }
+ }
+
+ /**
+ * Apply theme to all the items.
+ */
+ private void applyItemsAttrsTheme(Theme t) {
+ if (mItemsThemeAttrs == null) {
+ return;
+ }
+
+ boolean hasUnresolvedAttrs = false;
+
+ final int[][] themeAttrsList = mItemsThemeAttrs;
+ final int N = themeAttrsList.length;
+ for (int i = 0; i < N; i++) {
+ if (themeAttrsList[i] != null) {
+ final TypedArray a = t.resolveAttributes(themeAttrsList[i],
+ R.styleable.GradientColorItem);
+
+ // Extract the theme attributes, if any, before attempting to
+ // read from the typed array. This prevents a crash if we have
+ // unresolved attrs.
+ themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
+ if (themeAttrsList[i] != null) {
+ hasUnresolvedAttrs = true;
+ }
+
+ mItemColors[i] = a.getColor(R.styleable.GradientColorItem_color, mItemColors[i]);
+ mItemOffsets[i] = a.getFloat(R.styleable.GradientColorItem_offset, mItemOffsets[i]);
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "applyItemsAttrsTheme Colors[i] " + i + " " +
+ Integer.toHexString(mItemColors[i]));
+ Log.v(TAG, "Offsets[i] " + i + " " + mItemOffsets[i]);
+ }
+
+ // Account for any configuration changes.
+ mChangingConfigurations |= a.getChangingConfigurations();
+
+ a.recycle();
+ }
+ }
+
+ if (!hasUnresolvedAttrs) {
+ mItemsThemeAttrs = null;
+ }
+ }
+
+ private void onColorsChange() {
+ int[] tempColors = null;
+ float[] tempOffsets = null;
+
+ if (mItemColors != null) {
+ int length = mItemColors.length;
+ tempColors = new int[length];
+ tempOffsets = new float[length];
+
+ for (int i = 0; i < length; i++) {
+ tempColors[i] = mItemColors[i];
+ tempOffsets[i] = mItemOffsets[i];
+ }
+ } else {
+ if (mHasCenterColor) {
+ tempColors = new int[3];
+ tempColors[0] = mStartColor;
+ tempColors[1] = mCenterColor;
+ tempColors[2] = mEndColor;
+
+ tempOffsets = new float[3];
+ tempOffsets[0] = 0.0f;
+ // Since 0.5f is default value, try to take the one that isn't 0.5f
+ tempOffsets[1] = 0.5f;
+ tempOffsets[2] = 1f;
+ } else {
+ tempColors = new int[2];
+ tempColors[0] = mStartColor;
+ tempColors[1] = mEndColor;
+ }
+ }
+ if (tempColors.length < 2) {
+ Log.w(TAG, "<gradient> tag requires 2 color values specified!" + tempColors.length
+ + " " + tempColors);
+ }
+
+ if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
+ mShader = new LinearGradient(mStartX, mStartY, mEndX, mEndY, tempColors, tempOffsets,
+ Shader.TileMode.CLAMP);
+ } else {
+ if (mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+ mShader = new RadialGradient(mCenterX, mCenterY, mGradientRadius, tempColors,
+ tempOffsets, Shader.TileMode.CLAMP);
+ } else {
+ mShader = new SweepGradient(mCenterX, mCenterY, tempColors, tempOffsets);
+ }
+ }
+ mDefaultColor = tempColors[0];
+ }
+
+ /**
+ * For Gradient color, the default color is not very useful, since the gradient will override
+ * the color information anyway.
+ */
+ @Override
+ @ColorInt
+ public int getDefaultColor() {
+ return mDefaultColor;
+ }
+
+ /**
+ * Similar to ColorStateList, setup constant state and its factory.
+ * @hide only for resource preloading
+ */
+ @Override
+ public ConstantState<ComplexColor> getConstantState() {
+ if (mFactory == null) {
+ mFactory = new GradientColorFactory(this);
+ }
+ return mFactory;
+ }
+
+ private static class GradientColorFactory extends ConstantState<ComplexColor> {
+ private final GradientColor mSrc;
+
+ public GradientColorFactory(GradientColor src) {
+ mSrc = src;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mSrc.mChangingConfigurations;
+ }
+
+ @Override
+ public GradientColor newInstance() {
+ return mSrc;
+ }
+
+ @Override
+ public GradientColor newInstance(Resources res, Theme theme) {
+ return mSrc.obtainForTheme(theme);
+ }
+ }
+
+ /**
+ * Returns an appropriately themed gradient color.
+ *
+ * @param t the theme to apply
+ * @return a copy of the gradient color the theme applied, or the
+ * gradient itself if there were no unresolved theme
+ * attributes
+ * @hide only for resource preloading
+ */
+ @Override
+ public GradientColor obtainForTheme(Theme t) {
+ if (t == null || !canApplyTheme()) {
+ return this;
+ }
+
+ final GradientColor clone = new GradientColor(this);
+ clone.applyTheme(t);
+ return clone;
+ }
+
+ private void applyTheme(Theme t) {
+ if (mThemeAttrs != null) {
+ applyRootAttrsTheme(t);
+ }
+ if (mItemsThemeAttrs != null) {
+ applyItemsAttrsTheme(t);
+ }
+ onColorsChange();
+ }
+
+ private void applyRootAttrsTheme(Theme t) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.GradientColor);
+ // mThemeAttrs will be set to null if if there are no theme attributes in the
+ // typed array.
+ mThemeAttrs = a.extractThemeAttrs(mThemeAttrs);
+ // merging the attributes update inside the updateRootElementState().
+ updateRootElementState(a);
+
+ // Account for any configuration changes.
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+ }
+
+
+ /**
+ * Returns whether a theme can be applied to this gradient color, which
+ * usually indicates that the gradient color has unresolved theme
+ * attributes.
+ *
+ * @return whether a theme can be applied to this gradient color.
+ * @hide only for resource preloading
+ */
+ @Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null || mItemsThemeAttrs != null;
+ }
+
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e404429..4967d05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -56,6 +56,7 @@
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
import android.util.TypedValue;
+import android.util.Xml;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -115,8 +116,8 @@
private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
= new LongSparseArray<>();
- private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
- sPreloadedColorStateLists = new LongSparseArray<>();
+ private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+ sPreloadedComplexColors = new LongSparseArray<>();
// Pool of TypedArrays targeted to this Resources object.
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -133,7 +134,7 @@
private final Configuration mTmpConfig = new Configuration();
private final DrawableCache mDrawableCache = new DrawableCache(this);
private final DrawableCache mColorDrawableCache = new DrawableCache(this);
- private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
+ private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
new ConfigurationBoundResourceCache<>(this);
private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
new ConfigurationBoundResourceCache<>(this);
@@ -1987,7 +1988,7 @@
mDrawableCache.onConfigurationChange(configChanges);
mColorDrawableCache.onConfigurationChange(configChanges);
- mColorStateListCache.onConfigurationChange(configChanges);
+ mComplexColorCache.onConfigurationChange(configChanges);
mAnimatorCache.onConfigurationChange(configChanges);
mStateListAnimatorCache.onConfigurationChange(configChanges);
@@ -2613,6 +2614,82 @@
return dr;
}
+ /**
+ * Given the value and id, we can get the XML filename as in value.data, based on that, we
+ * first try to load CSL from the cache. If not found, try to get from the constant state.
+ * Last, parse the XML and generate the CSL.
+ */
+ private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+ final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+ ComplexColor complexColor = cache.getInstance(key, theme);
+ if (complexColor != null) {
+ return complexColor;
+ }
+
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
+
+ if (factory != null) {
+ complexColor = factory.newInstance(this, theme);
+ }
+ if (complexColor == null) {
+ complexColor = loadComplexColorForCookie(value, id, theme);
+ }
+
+ if (complexColor != null) {
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, complexColor.getConstantState());
+ }
+ } else {
+ cache.put(key, theme, complexColor.getConstantState());
+ }
+ }
+ return complexColor;
+ }
+
+ @Nullable
+ public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("loadComplexColor", name);
+ }
+ }
+
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+
+ // Handle inline color definitions.
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+ && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ return getColorStateListFromInt(value, key);
+ }
+
+ final String file = value.string.toString();
+
+ ComplexColor complexColor;
+ if (file.endsWith(".xml")) {
+ try {
+ complexColor = loadComplexColorFromName(theme, value, id);
+ } catch (Exception e) {
+ final NotFoundException rnf = new NotFoundException(
+ "File " + file + " from complex color resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ } else {
+ throw new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id) + ": .xml extension required");
+ }
+
+ return complexColor;
+ }
+
@Nullable
ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
throws NotFoundException {
@@ -2626,63 +2703,57 @@
final long key = (((long) value.assetCookie) << 32) | value.data;
- ColorStateList csl;
-
// Handle inline color definitions.
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
- if (factory != null) {
- return factory.newInstance();
- }
-
- csl = ColorStateList.valueOf(value.data);
-
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedColorStateLists.put(key, csl.getConstantState());
- }
- }
-
- return csl;
+ return getColorStateListFromInt(value, key);
}
- final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
- csl = cache.getInstance(key, theme);
- if (csl != null) {
- return csl;
+ ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
+ if (complexColor != null && complexColor instanceof ColorStateList) {
+ return (ColorStateList) complexColor;
}
- final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ throw new NotFoundException(
+ "Can't find ColorStateList from drawable resource ID #0x"
+ + Integer.toHexString(id));
+ }
+
+ @NonNull
+ private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
+ ColorStateList csl;
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
if (factory != null) {
- csl = factory.newInstance(this, theme);
+ return (ColorStateList) factory.newInstance();
}
- if (csl == null) {
- csl = loadColorStateListForCookie(value, id, theme);
- }
+ csl = ColorStateList.valueOf(value.data);
- if (csl != null) {
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedColorStateLists.put(key, csl.getConstantState());
- }
- } else {
- cache.put(key, theme, csl.getConstantState());
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, csl.getConstantState());
}
}
return csl;
}
- private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
+ /**
+ * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+ * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+ *
+ * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+ * and selector tag.
+ *
+ * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+ */
+ @Nullable
+ private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
if (value.string == null) {
throw new UnsupportedOperationException(
- "Can't convert to color state list: type=0x" + value.type);
+ "Can't convert to ComplexColor: type=0x" + value.type);
}
final String file = value.string.toString();
@@ -2692,29 +2763,45 @@
if ((id >>> 24) == 0x1) {
final String name = getResourceName(id);
if (name != null) {
- Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
+ Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
+ ": " + name + " at " + file);
}
}
}
if (DEBUG_LOAD) {
- Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
+ Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
}
- final ColorStateList csl;
+ ComplexColor complexColor = null;
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
if (file.endsWith(".xml")) {
try {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "colorstatelist");
- csl = ColorStateList.createFromXml(this, rp, theme);
- rp.close();
+ final XmlResourceParser parser = loadXmlResourceParser(
+ file, id, value.assetCookie, "ComplexColor");
+
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Seek parser to start tag.
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ final String name = parser.getName();
+ if (name.equals("gradient")) {
+ complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
+ } else if (name.equals("selector")) {
+ complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
+ }
+ parser.close();
} catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
final NotFoundException rnf = new NotFoundException(
- "File " + file + " from color state list resource ID #0x"
+ "File " + file + " from ComplexColor resource ID #0x"
+ Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
@@ -2727,7 +2814,7 @@
}
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- return csl;
+ return complexColor;
}
/**
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cc65e1e..6067577 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -454,6 +454,39 @@
}
/**
+ * Retrieve the ComplexColor for the attribute at <var>index</var>.
+ * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple
+ * color value or a {@link android.content.res.GradientColor}
+ * <p>
+ * This method will return {@code null} if the attribute is not defined or
+ * is not an integer color, color state list or GradientColor.
+ *
+ * @param index Index of attribute to retrieve.
+ *
+ * @return ComplexColor for the attribute, or {@code null} if not defined.
+ * @throws RuntimeException if the attribute if the TypedArray has already
+ * been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer color, color state list or GradientColor.
+ */
+ @Nullable
+ public ComplexColor getComplexColor(@StyleableRes int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
+ final TypedValue value = mValue;
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index + ": " + value);
+ }
+ return mResources.loadComplexColor(value, value.resourceId, mTheme);
+ }
+ return null;
+ }
+
+ /**
* Retrieve the ColorStateList for the attribute at <var>index</var>.
* The value may be either a single solid color or a reference to
* a color or complex {@link android.content.res.ColorStateList}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e5efd56..841e5b0 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -17,8 +17,10 @@
package android.hardware;
-import android.os.Build;
import android.annotation.SystemApi;
+import android.os.Build;
+
+import java.util.UUID;
/**
* Class representing a sensor. Use {@link SensorManager#getSensorList} to get
@@ -557,6 +559,8 @@
* Similar to {@link #TYPE_ROTATION_VECTOR}, with additional delta
* translation from an arbitrary reference point.
*
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ *
* Can use camera, depth sensor etc to compute output value.
*
* This is expected to be a high power sensor and expected only to be
@@ -574,9 +578,78 @@
*/
public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
+ /**
+ * A constant describing a stationary detect sensor.
+ *
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ *
+ */
+ public static final int TYPE_STATIONARY_DETECT = 29;
+
+ /**
+ * A constant string describing a stationary detection sensor.
+ *
+ * @see #TYPE_STATIONARY_DETECT
+ */
+ public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
+
+ /**
+ * A constant describing a motion detect sensor.
+ *
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ *
+ */
+ public static final int TYPE_MOTION_DETECT = 30;
+
+ /**
+ * A constant string describing a motion detection sensor.
+ *
+ * @see #TYPE_MOTION_DETECT
+ */
+ public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
+
+ /**
+ * A constant describing a motion detect sensor.
+ *
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ *
+ */
+ public static final int TYPE_HEART_BEAT = 31;
+
+ /**
+ * A constant string describing a heart beat sensor.
+ *
+ * @see #TYPE_HEART_BEAT
+ */
+
+ public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
+ /**
+ * A constant describing a dynamic sensor meta event sensor.
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from
+ * the system. This sensor type should always use special trigger report mode ({@code
+ * SensorManager.REPORTING_MODE_SPECIAL_TRIGGER}).
+ *
+ * @hide This sensor is expected to be used only by system services.
+ */
+ @SystemApi
+ public static final int TYPE_DYNAMIC_SENSOR_META = 32;
+
+ /**
+ * A constant string describing a dynamic sensor meta event sensor.
+ *
+ * @see #TYPE_DYNAMIC_SENSOR_META
+ *
+ * @hide This sensor is expected to only be used by the system service
+ */
+ @SystemApi
+ public static final String STRING_TYPE_DYNAMIC_SENSOR_META =
+ "android.sensor.dynamic_sensor_meta";
+
/**
* A constant describing all sensor types.
*/
+
public static final int TYPE_ALL = -1;
// If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
@@ -660,7 +733,11 @@
1, // SENSOR_TYPE_PICK_UP_GESTURE
1, // SENSOR_TYPE_WRIST_TILT_GESTURE
1, // SENSOR_TYPE_DEVICE_ORIENTATION
- 16, // SENSOR_TYPE_POSE_6DOF
+ 16,// SENSOR_TYPE_POSE_6DOF
+ 1, // SENSOR_TYPE_STATIONARY_DETECT
+ 1, // SENSOR_TYPE_MOTION_DETECT
+ 1, // SENSOR_TYPE_HEART_BEAT
+ 2, // SENSOR_TYPE_DYNAMIC_SENSOR_META
};
/**
@@ -686,12 +763,10 @@
}
int offset = sensor.mType;
if (offset >= sSensorReportingModes.length) {
- // we don't know about this sensor, so this is probably a
- // vendor-defined sensor, in that case, we don't know how many value
- // it has
- // so we return the maximum and assume the app will know.
- // FIXME: sensor HAL should advertise how much data is returned per
- // sensor
+ // we don't know about this sensor, so this is probably a vendor-defined sensor, in that
+ // case, we don't know how many value it has so we return the maximum and assume the app
+ // will know.
+ // FIXME: sensor HAL should advertise how much data is returned per sensor
return 16;
}
return sSensorReportingModes[offset];
@@ -715,6 +790,7 @@
private String mRequiredPermission;
private int mMaxDelay;
private int mFlags;
+ private UUID mUuid;
Sensor() {
}
@@ -803,6 +879,13 @@
}
/**
+ * @return The type of this sensor as a string.
+ */
+ public UUID getUuid() {
+ return mUuid;
+ }
+
+ /**
* @hide
* @return The permission required to access this sensor. If empty, no permission is required.
*/
@@ -985,6 +1068,9 @@
case TYPE_DEVICE_ORIENTATION:
mStringType = STRING_TYPE_DEVICE_ORIENTATION;
return true;
+ case TYPE_DYNAMIC_SENSOR_META:
+ mStringType = STRING_TYPE_DYNAMIC_SENSOR_META;
+ return true;
default:
return false;
}
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
new file mode 100644
index 0000000..8e5b8a3
--- /dev/null
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class represents a {@link android.hardware.Sensor Sensor} additional information frame,
+ * which is reported through listener callback {@link
+ * android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
+ *
+ * @see SensorManager
+ * @see SensorEventListener3
+ * @see Sensor
+ *
+ */
+
+public class SensorAdditionalInfo {
+
+ /**
+ * The sensor that generated this event. See
+ * {@link android.hardware.SensorManager SensorManager} for details.
+ */
+ public final Sensor sensor;
+
+ /**
+ * Type of this additional info frame.
+ */
+ public final int type;
+
+ /**
+ * Sequence number of frame for a certain type.
+ */
+ public final int serial;
+
+ /**
+ * Additional info payload data represented in float values. Depending on the type of
+ * information, this may be null.
+ */
+ public final float[] floatValues;
+
+ /**
+ * Additional info payload data represented in int values. Depending on the type of information,
+ * this may be null.
+ */
+ public final int[] intValues;
+
+ /**
+ * Typical values of additional infomation type. The set of values is subject to extension in
+ * newer versions and vendors have the freedom of define their own custom values.
+ *
+ * @hide
+ */
+ @IntDef({TYPE_FRAME_BEGIN, TYPE_FRAME_END, TYPE_UNTRACKED_DELAY, TYPE_INTERNAL_TEMPERATURE,
+ TYPE_VEC3_CALIBRATION, TYPE_SENSOR_PLACEMENT, TYPE_SAMPLING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AdditionalInfoType {}
+
+ /**
+ * Mark the beginning of a set of additional info frames.
+ */
+ public static final int TYPE_FRAME_BEGIN = 0;
+
+ /**
+ * Mark the end of a set of additional info frames.
+ */
+ public static final int TYPE_FRAME_END = 1;
+
+ /**
+ * Untracked delay. Delays that are introduced by data processing, such as filtering, which is
+ * not taken into account by sensor timestamps.
+ *
+ * Payload:
+ * floatValues[0]: delay estimation in seconds
+ * floatValues[1]: delay estimation standard deviation
+ */
+ public static final int TYPE_UNTRACKED_DELAY = 0x10000;
+
+ /**
+ * Internal temperature. Sensor hardware device internal temperature.
+ *
+ * Payload:
+ * floatValues[0]: internal temperature in Celsius.
+ */
+ public static final int TYPE_INTERNAL_TEMPERATURE = 0x10001;
+
+ /**
+ * Vector calibration parameter. Calibration applied to a sensor with 3 elements vector output,
+ * such as accelerometer, gyro, etc.
+ *
+ * Payload:
+ * floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+ * any linear transformation, including rotation, scaling, shear, shift.
+ */
+ public static final int TYPE_VEC3_CALIBRATION = 0x10002;
+
+ /**
+ * Sensor placement. Describes location and installation angle of the sensor device.
+ *
+ * Payload:
+ * floatValues[0..11]: First 3 rows of homogeneous matrix in row major order that describes
+ * the location and orientation of the sensor. Origin of reference will be the mobile device
+ * geometric sensor. Reference frame is defined as the same as Android sensor frame.
+ */
+ public static final int TYPE_SENSOR_PLACEMENT = 0x10003;
+
+ /**
+ * Sampling parameter. Describes the raw sample period and estimated jitter of sample time in
+ * terms of standard deviation.
+ *
+ * Payload:
+ * floatValues[0]: raw sample period in seconds.
+ * floatValues[1]: standard deviation of sampling period.
+ */
+ public static final int TYPE_SAMPLING = 0x10004;
+
+ SensorAdditionalInfo(
+ Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
+ sensor = aSensor;
+ type = aType;
+ serial = aSerial;
+ intValues = aIntValues;
+ floatValues = aFloatValues;
+ }
+}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 416c74c..35c96f7 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -396,7 +396,7 @@
* dv = 216.7 *
* (rh / 100.0 * 6.112 * Math.exp(17.62 * t / (243.12 + t)) / (273.15 + t));
* </pre>
- *
+ *
* <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
* </h4>
*
@@ -531,6 +531,53 @@
*
* </ul>
*
+ * <h4>{@link android.hardware.Sensor#TYPE_STATIONARY_DETECT
+ * Sensor.TYPE_STATIONARY_DETECT}:</h4>
+ *
+ * A TYPE_STATIONARY_DETECT event is produced if the device has been
+ * stationary for at least 5 seconds with a maximal latency of 5
+ * additional seconds. ie: it may take up anywhere from 5 to 10 seconds
+ * afte the device has been at rest to trigger this event.
+ *
+ * The only allowed value is 1.0.
+ *
+ * <ul>
+ * <li> values[0]: 1.0 </li>
+ * </ul>
+ *
+ * <h4>{@link android.hardware.Sensor#TYPE_MOTION_DETECT
+ * Sensor.TYPE_MOTION_DETECT}:</h4>
+ *
+ * A TYPE_MOTION_DETECT event is produced if the device has been in
+ * motion for at least 5 seconds with a maximal latency of 5
+ * additional seconds. ie: it may take up anywhere from 5 to 10 seconds
+ * afte the device has been at rest to trigger this event.
+ *
+ * The only allowed value is 1.0.
+ *
+ * <ul>
+ * <li> values[0]: 1.0 </li>
+ * </ul>
+ *
+ * <h4>{@link android.hardware.Sensor#TYPE_HEART_BEAT
+ * Sensor.TYPE_HEART_BEAT}:</h4>
+ *
+ * A sensor of this type returns an event everytime a hear beat peak is
+ * detected.
+ *
+ * Peak here ideally corresponds to the positive peak in the QRS complex of
+ * an ECG signal.
+ *
+ * <ul>
+ * <li> values[0]: confidence</li>
+ * </ul>
+ *
+ * <p>
+ * A confidence value of 0.0 indicates complete uncertainty - that a peak
+ * is as likely to be at the indicated timestamp as anywhere else.
+ * A confidence value of 1.0 indicates complete certainly - that a peak is
+ * completely unlikely to be anywhere else on the QRS complex.
+ * </p>
*/
public final float[] values;
diff --git a/core/java/android/hardware/SensorEventCallback.java b/core/java/android/hardware/SensorEventCallback.java
new file mode 100644
index 0000000..bac212a
--- /dev/null
+++ b/core/java/android/hardware/SensorEventCallback.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * Used for receiving sensor additional information frames.
+ */
+public abstract class SensorEventCallback implements SensorEventListener2 {
+
+ /**
+ * Called when sensor values have changed.
+ *
+ * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
+ */
+ @Override
+ public void onSensorChanged(SensorEvent event) {}
+
+ /**
+ * Called when the accuracy of the registered sensor has changed.
+ *
+ * @see android.hardware.SensorEventListener#onAccuracyChanged(Sensor, int)
+ */
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+ /**
+ * Called after flush() is completed.
+ *
+ * @see android.hardware.SensorEventListener2#onFlushCompleted(Sensor)
+ */
+ @Override
+ public void onFlushCompleted(Sensor sensor) {}
+
+ /**
+ * Called when a sensor additional information frame is available.
+ *
+ * @param info A {@link android.hardware.SensorAdditionalInfo SensorAdditionalInfo} frame
+ * reported from sensor hardware.
+ */
+ public void onSensorAdditionalInfo(SensorAdditionalInfo info) {}
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5d405f9..f0b17c30 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -377,6 +377,12 @@
protected abstract List<Sensor> getFullSensorList();
/**
+ * Gets the full list of dynamic sensors that are available.
+ * @hide
+ */
+ protected abstract List<Sensor> getFullDynamicSensorList();
+
+ /**
* @return available sensors.
* @deprecated This method is deprecated, use
* {@link SensorManager#getSensorList(int)} instead
@@ -430,6 +436,38 @@
}
/**
+ * Use this method to get a list of available dynamic sensors of a certain type.
+ * Make multiple calls to get sensors of different types or use
+ * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all dynamic sensors.
+ *
+ * <p class="note">
+ * NOTE: Both wake-up and non wake-up sensors matching the given type are
+ * returned. Check {@link Sensor#isWakeUpSensor()} to know the wake-up properties
+ * of the returned {@link Sensor}.
+ * </p>
+ *
+ * @param type of sensors requested
+ *
+ * @return a list of dynamic sensors matching the requested type.
+ *
+ * @see Sensor
+ */
+ public List<Sensor> getDynamicSensorList(int type) {
+ // cache the returned lists the first time
+ final List<Sensor> fullList = getFullDynamicSensorList();
+ if (type == Sensor.TYPE_ALL) {
+ return Collections.unmodifiableList(fullList);
+ } else {
+ List<Sensor> list = new ArrayList();
+ for (Sensor i : fullList) {
+ if (i.getType() == type)
+ list.add(i);
+ }
+ return Collections.unmodifiableList(list);
+ }
+ }
+
+ /**
* Use this method to get the default sensor for a given type. Note that the
* returned sensor could be a composite sensor, and its data could be
* averaged or filtered. If you need to access the raw sensors use
@@ -841,6 +879,86 @@
/** @hide */
protected abstract boolean flushImpl(SensorEventListener listener);
+
+ /**
+ * Used for receiving notifications from the SensorManager when dynamic sensors are connected or
+ * disconnected.
+ */
+ public static abstract class DynamicSensorConnectionCallback {
+ /**
+ * Called when there is a dynamic sensor being connected to the system.
+ *
+ * @param sensor the newly connected sensor. See {@link android.hardware.Sensor Sensor}.
+ */
+ public void onDynamicSensorConnected(Sensor sensor) {}
+
+ /**
+ * Called when there is a dynamic sensor being disconnected from the system.
+ *
+ * @param sensor the disconnected sensor. See {@link android.hardware.Sensor Sensor}.
+ */
+ public void onDynamicSensorDisconnected(Sensor sensor) {}
+ }
+
+
+ /**
+ * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * registration with the already registered callback object will have no additional effect.
+ *
+ * @param callback An object that implements the
+ * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback}
+ * interface for receiving callbacks.
+ * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+ *
+ * @throws IllegalArgumentException when callback is null.
+ */
+ public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ registerDynamicSensorCallback(callback, null);
+ }
+
+ /**
+ * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+ * registration with the already registered callback object will have no additional effect.
+ *
+ * @param callback An object that implements the
+ * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback} interface for receiving callbacks.
+ * @param handler The {@link android.os.Handler Handler} the {@link
+ * android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * sensor connection events} will be delivered to.
+ *
+ * @throws IllegalArgumentException when callback is null.
+ */
+ public void registerDynamicSensorCallback(
+ DynamicSensorConnectionCallback callback, Handler handler) {
+ registerDynamicSensorCallbackImpl(callback, handler);
+ }
+
+ /**
+ * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+ * callback.
+ *
+ * @param callback An object that implements the
+ * {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+ * DynamicSensorConnectionCallback}
+ * interface for receiving callbacks.
+ */
+ public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+ unregisterDynamicSensorCallbackImpl(callback);
+ }
+
+ /** @hide */
+ protected abstract void registerDynamicSensorCallbackImpl(
+ DynamicSensorConnectionCallback callback, Handler handler);
+
+ /** @hide */
+ protected abstract void unregisterDynamicSensorCallbackImpl(
+ DynamicSensorConnectionCallback callback);
+
/**
* <p>
* Computes the inclination matrix <b>I</b> as well as the rotation matrix
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 2fe8fb6..c4afbfb 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -17,7 +17,10 @@
package android.hardware;
import android.Manifest;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
@@ -32,6 +35,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Sensor manager implementation that communicates with the built-in
@@ -40,10 +44,14 @@
* @hide
*/
public class SystemSensorManager extends SensorManager {
+ //TODO: disable extra logging before release
+ private static boolean DEBUG_DYNAMIC_SENSOR = true;
+
private static native void nativeClassInit();
private static native long nativeCreate(String opPackageName);
private static native boolean nativeGetSensorAtIndex(long nativeInstance,
Sensor sensor, int index);
+ private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
private static boolean sSensorModuleInitialized = false;
@@ -52,7 +60,10 @@
private final Object mLock = new Object();
private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
- private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>();
+ private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
+ private boolean mDynamicSensorListDirty = true;
+
+ private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
// Listener list
private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
@@ -60,6 +71,11 @@
private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
new HashMap<TriggerEventListener, TriggerEventQueue>();
+ // Dynamic Sensor callbacks
+ private HashMap<DynamicSensorConnectionCallback, Handler>
+ mDynamicSensorCallbacks = new HashMap<>();
+ private BroadcastReceiver mDynamicSensorBroadcastReceiver;
+
// Looper associated with the context in which this instance was created.
private final Looper mMainLooper;
private final int mTargetSdkLevel;
@@ -84,7 +100,7 @@
Sensor sensor = new Sensor();
if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
mFullSensorsList.add(sensor);
- mHandleToSensor.append(sensor.getHandle(), sensor);
+ mHandleToSensor.put(sensor.getHandle(), sensor);
}
}
}
@@ -96,6 +112,15 @@
return mFullSensorsList;
}
+ /** @hide */
+ @Override
+ protected List<Sensor> getFullDynamicSensorList() {
+ // only set up broadcast receiver if the application tries to find dynamic sensors or
+ // explicitly register a DynamicSensorConnectionCallback
+ setupDynamicSensorBroadcastReceiver();
+ updateDynamicSensorList();
+ return mFullDynamicSensorsList;
+ }
/** @hide */
@Override
@@ -274,6 +299,187 @@
}
}
+ private void cleanupSensorConnection(Sensor sensor) {
+ mHandleToSensor.remove(sensor.getHandle());
+
+ if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+ synchronized(mTriggerListeners) {
+ for (TriggerEventListener l: mTriggerListeners.keySet()) {
+ if (DEBUG_DYNAMIC_SENSOR){
+ Log.i(TAG, "removed trigger listener" + l.toString() +
+ " due to sensor disconnection");
+ }
+ cancelTriggerSensorImpl(l, sensor, true);
+ }
+ }
+ } else {
+ synchronized(mSensorListeners) {
+ for (SensorEventListener l: mSensorListeners.keySet()) {
+ if (DEBUG_DYNAMIC_SENSOR){
+ Log.i(TAG, "removed event listener" + l.toString() +
+ " due to sensor disconnection");
+ }
+ unregisterListenerImpl(l, sensor);
+ }
+ }
+ }
+ }
+
+ private void updateDynamicSensorList() {
+ synchronized(mFullDynamicSensorsList) {
+ if (mDynamicSensorListDirty) {
+ List<Sensor> list = new ArrayList<>();
+ nativeGetDynamicSensors(mNativeInstance, list);
+
+ final List<Sensor> updatedList = new ArrayList<>();
+ final List<Sensor> addedList = new ArrayList<>();
+ final List<Sensor> removedList = new ArrayList<>();
+
+ boolean changed = diffSortedSensorList(
+ mFullDynamicSensorsList, list, updatedList, addedList, removedList);
+
+ if (changed) {
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "DYNS dynamic sensor list cached should be updated");
+ }
+ mFullDynamicSensorsList = updatedList;
+
+ for (Sensor s: addedList) {
+ mHandleToSensor.put(s.getHandle(), s);
+ }
+
+ Handler mainHandler = new Handler(mContext.getMainLooper());
+
+ for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+ mDynamicSensorCallbacks.entrySet()) {
+ final DynamicSensorConnectionCallback callback = entry.getKey();
+ Handler handler =
+ entry.getValue() == null ? mainHandler : entry.getValue();
+
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (Sensor s: addedList) {
+ callback.onDynamicSensorConnected(s);
+ }
+ for (Sensor s: removedList) {
+ callback.onDynamicSensorDisconnected(s);
+ }
+ }
+ });
+ }
+
+ for (Sensor s: removedList) {
+ cleanupSensorConnection(s);
+ }
+ }
+
+ mDynamicSensorListDirty = false;
+ }
+ }
+ }
+
+ private void setupDynamicSensorBroadcastReceiver() {
+ if (mDynamicSensorBroadcastReceiver == null) {
+ mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) {
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast");
+ }
+ // Dynamic sensors probably changed
+ mDynamicSensorListDirty = true;
+ updateDynamicSensorList();
+ }
+ }
+ };
+
+ IntentFilter filter = new IntentFilter("dynamic_sensor_change");
+ filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
+ mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
+ }
+ }
+
+ private void teardownDynamicSensorBroadcastReceiver() {
+ mDynamicSensorCallbacks.clear();
+ mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
+ mDynamicSensorBroadcastReceiver = null;
+ }
+
+ /** @hide */
+ protected void registerDynamicSensorCallbackImpl(
+ DynamicSensorConnectionCallback callback, Handler handler) {
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "DYNS Register dynamic sensor callback");
+ }
+
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null");
+ }
+ if (mDynamicSensorCallbacks.containsKey(callback)) {
+ // has been already registered, ignore
+ return;
+ }
+
+ setupDynamicSensorBroadcastReceiver();
+ mDynamicSensorCallbacks.put(callback, handler);
+ }
+
+ /** @hide */
+ protected void unregisterDynamicSensorCallbackImpl(
+ DynamicSensorConnectionCallback callback) {
+ if (DEBUG_DYNAMIC_SENSOR) {
+ Log.i(TAG, "Removing dynamic sensor listerner");
+ }
+ mDynamicSensorCallbacks.remove(callback);
+ }
+
+ /*
+ * Find the difference of two List<Sensor> assuming List are sorted by handle of sensor,
+ * assuming the input list is already sorted by handle. Inputs are ol and nl; outputs are
+ * updated, added and removed. Any of the output lists can be null in case the result is not
+ * interested.
+ */
+ private static boolean diffSortedSensorList(
+ List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated,
+ List<Sensor> added, List<Sensor> removed) {
+
+ boolean changed = false;
+
+ int i = 0, j = 0;
+ while (true) {
+ if (j < oldList.size() && ( i >= newList.size() ||
+ newList.get(i).getHandle() > oldList.get(j).getHandle()) ) {
+ changed = true;
+ if (removed != null) {
+ removed.add(oldList.get(j));
+ }
+ ++j;
+ } else if (i < newList.size() && ( j >= oldList.size() ||
+ newList.get(i).getHandle() < oldList.get(j).getHandle())) {
+ changed = true;
+ if (added != null) {
+ added.add(newList.get(i));
+ }
+ if (updated != null) {
+ updated.add(newList.get(i));
+ }
+ ++i;
+ } else if (i < newList.size() && j < oldList.size() &&
+ newList.get(i).getHandle() == oldList.get(j).getHandle()) {
+ if (updated != null) {
+ updated.add(oldList.get(j));
+ }
+ ++i;
+ ++j;
+ } else {
+ break;
+ }
+ }
+ return changed;
+ }
+
/*
* BaseEventQueue is the communication channel with the sensor service,
* SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
@@ -284,7 +490,7 @@
*/
private static abstract class BaseEventQueue {
private static native long nativeInitBaseEventQueue(long nativeManager,
- WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
+ WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
String packageName, int mode, String opPackageName);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
int maxBatchReportLatencyUs);
@@ -297,9 +503,7 @@
private long nSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
- protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
private final CloseGuard mCloseGuard = CloseGuard.get();
- private final float[] mScratch = new float[16];
protected final SystemSensorManager mManager;
protected static final int OPERATING_MODE_NORMAL = 0;
@@ -308,7 +512,7 @@
BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
if (packageName == null) packageName = "";
nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
- new WeakReference<>(this), looper.getQueue(), mScratch,
+ new WeakReference<>(this), looper.getQueue(),
packageName, mode, manager.mContext.getOpPackageName());
mCloseGuard.open("dispose");
mManager = manager;
@@ -348,7 +552,7 @@
mActiveSensors.put(handle, false);
removeSensorEvent(sensor);
} else {
- // it should never happen -- just ignore.
+ // sensor just disconnected -- just ignore.
}
}
}
@@ -420,6 +624,11 @@
long timestamp);
protected abstract void dispatchFlushCompleteEvent(int handle);
+ protected void dispatchAdditionalInfoEvent(
+ int handle, int type, int serial, float[] floatValues, int[] intValues) {
+ // default implementation is do nothing
+ }
+
protected abstract void addSensorEvent(Sensor sensor);
protected abstract void removeSensorEvent(Sensor sensor);
}
@@ -456,6 +665,11 @@
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
final Sensor sensor = mManager.mHandleToSensor.get(handle);
+ if (sensor == null) {
+ // sensor disconnected
+ return;
+ }
+
SensorEvent t = null;
synchronized (mSensorsEvents) {
t = mSensorsEvents.get(handle);
@@ -481,14 +695,37 @@
mListener.onSensorChanged(t);
}
+ // Called from native code.
@SuppressWarnings("unused")
+ @Override
protected void dispatchFlushCompleteEvent(int handle) {
if (mListener instanceof SensorEventListener2) {
final Sensor sensor = mManager.mHandleToSensor.get(handle);
+ if (sensor == null) {
+ // sensor disconnected
+ return;
+ }
((SensorEventListener2)mListener).onFlushCompleted(sensor);
}
return;
}
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ @Override
+ protected void dispatchAdditionalInfoEvent(
+ int handle, int type, int serial, float[] floatValues, int[] intValues) {
+ if (mListener instanceof SensorEventCallback) {
+ final Sensor sensor = mManager.mHandleToSensor.get(handle);
+ if (sensor == null) {
+ // sensor disconnected
+ return;
+ }
+ SensorAdditionalInfo info =
+ new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
+ ((SensorEventCallback)mListener).onSensorAdditionalInfo(info);
+ }
+ }
}
static final class TriggerEventQueue extends BaseEventQueue {
@@ -523,6 +760,10 @@
protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp) {
final Sensor sensor = mManager.mHandleToSensor.get(handle);
+ if (sensor == null) {
+ // sensor disconnected
+ return;
+ }
TriggerEvent t = null;
synchronized (mTriggerEvents) {
t = mTriggerEvents.get(handle);
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 28bb22a..6aacc9c 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -575,14 +575,16 @@
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3}) devices
* support at least the following stream combinations for creating a reprocessable capture
* session in addition to those for
- * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} devices. Note that targets in the "Reprocess-only target" column may only be
- * used as an output target for a reprocess capture request, not as an output to a regular capture request.
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} devices. Note that while
+ * the second configuration allows for configuring {@code MAXIMUM} {@code YUV} and {@code JPEG}
+ * outputs at the same time, that configuration is not listed for regular capture sessions, and
+ * therefore simultaneous output to both targets is not allowed.
*
* <table>
* <tr><th colspan="13">LEVEL-3 additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is always guaranteed.</th></tr>
- * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th colspan="2" id="rb">Reprocess-only target</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th colspan="2" id="rb">Target 5</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
- * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>In-app viewfinder analysis with ZSL and RAW.</td> </tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>In-app viewfinder analysis with ZSL and RAW.</td> </tr>
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td>In-app viewfinder analysis with ZSL, RAW, and JPEG reprocessing output.</td> </tr>
* </table><br>
* </p>
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index 584008c..2cafa08 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -16,8 +16,10 @@
package android.hardware.input;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.LocaleList;
import java.util.Locale;
@@ -32,7 +34,8 @@
private final String mLabel;
private final String mCollection;
private final int mPriority;
- private final Locale[] mLocales;
+ @NonNull
+ private final LocaleList mLocales;
private final int mVendorId;
private final int mProductId;
@@ -47,16 +50,12 @@
};
public KeyboardLayout(String descriptor, String label, String collection, int priority,
- Locale[] locales, int vid, int pid) {
+ LocaleList locales, int vid, int pid) {
mDescriptor = descriptor;
mLabel = label;
mCollection = collection;
mPriority = priority;
- if (locales != null) {
- mLocales = locales;
- } else {
- mLocales = new Locale[0];
- }
+ mLocales = locales;
mVendorId = vid;
mProductId = pid;
}
@@ -66,11 +65,7 @@
mLabel = source.readString();
mCollection = source.readString();
mPriority = source.readInt();
- int N = source.readInt();
- mLocales = new Locale[N];
- for (int i = 0; i < N; i++) {
- mLocales[i] = Locale.forLanguageTag(source.readString());
- }
+ mLocales = LocaleList.CREATOR.createFromParcel(source);
mVendorId = source.readInt();
mProductId = source.readInt();
}
@@ -108,7 +103,7 @@
* This may be empty if a locale has not been assigned to this keyboard layout.
* @return The keyboard layout's intended locale.
*/
- public Locale[] getLocales() {
+ public LocaleList getLocales() {
return mLocales;
}
@@ -141,14 +136,7 @@
dest.writeString(mLabel);
dest.writeString(mCollection);
dest.writeInt(mPriority);
- if (mLocales != null) {
- dest.writeInt(mLocales.length);
- for (Locale l : mLocales) {
- dest.writeString(l.toLanguageTag());
- }
- } else {
- dest.writeInt(0);
- }
+ mLocales.writeToParcel(dest, 0);
dest.writeInt(mVendorId);
dest.writeInt(mProductId);
}
diff --git a/core/java/android/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
new file mode 100644
index 0000000..1a9221a
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
new file mode 100644
index 0000000..e47c541
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubInfo {
+ private int mId;
+ private String mName;
+ private String mVendor;
+ private String mToolchain;
+ private int mPlatformVersion;
+ private int mStaticSwVersion;
+ private int mToolchainVersion;
+ private float mPeakMips;
+ private float mStoppedPowerDrawMw;
+ private float mSleepPowerDrawMw;
+ private float mPeakPowerDrawMw;
+
+ private int[] mSupportedSensors;
+
+ private MemoryRegion[] mMemoryRegions;
+
+ public ContextHubInfo() {
+ }
+
+ /**
+ * get the context hub unique identifer
+ *
+ * @return int - unique system wide identifier
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * set the context hub unique identifer
+ *
+ * @param id - unique system wide identifier for the hub
+ */
+ public void setId(int id) {
+ mId = id;
+ }
+
+ /**
+ * get a string as a hub name
+ *
+ * @return String - a name for the hub
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set a string as the hub name
+ *
+ * @param String - the name for the hub
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * get a string as the vendor name
+ *
+ * @return String - a name for the vendor
+ */
+ public String getVendor() {
+ return mVendor;
+ }
+
+ /**
+ * set a string as the vendor name
+ *
+ * @param String - a name for the vendor
+ */
+ public void setVendor(String vendor) {
+ mVendor = vendor;
+ }
+
+ /**
+ * get tool chain string
+ *
+ * @return String - description of the tool chain
+ */
+ public String getToolchain() {
+ return mToolchain;
+ }
+
+ /**
+ * set tool chain string
+ *
+ * @param String - description of the tool chain
+ */
+ public void setToolchain(String toolchain) {
+ mToolchain = toolchain;
+ }
+
+ /**
+ * get platform version
+ *
+ * @return int - platform version number
+ */
+ public int getPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ /**
+ * set platform version
+ *
+ * @param platformVersion - platform version number
+ */
+ public void setPlatformVersion(int platformVersion) {
+ mPlatformVersion = platformVersion;
+ }
+
+ /**
+ * get static platform version number
+ *
+ * @return int - platform version number
+ */
+ public int getStaticSwVersion() {
+ return mStaticSwVersion;
+ }
+
+ /**
+ * set platform software version
+ *
+ * @param staticSwVersion - platform static s/w version number
+ */
+ public void setStaticSwVersion(int staticSwVersion) {
+ mStaticSwVersion = staticSwVersion;
+ }
+
+ /**
+ * get the tool chain version
+ *
+ * @return int - the tool chain version
+ */
+ public int getToolchainVersion() {
+ return mToolchainVersion;
+ }
+
+ /**
+ * set the tool chain version number
+ *
+ * @param toolchainVersion - tool chain version number
+ */
+ public void setToolchainVersion(int toolchainVersion) {
+ mToolchainVersion = toolchainVersion;
+ }
+
+ /**
+ * get the peak processing mips the hub can support
+ *
+ * @return float - peak MIPS that this hub can deliver
+ */
+ public float getPeakMips() {
+ return mPeakMips;
+ }
+
+ /**
+ * set the peak mips that this hub can support
+ *
+ * @param peakMips - peak mips this hub can deliver
+ */
+ public void setPeakMips(float peakMips) {
+ mPeakMips = peakMips;
+ }
+
+ /**
+ * get the stopped power draw in milliwatts
+ * This assumes that the hub enter a stopped state - which is
+ * different from the sleep state. Latencies on exiting the
+ * sleep state are typically higher and expect to be in multiple
+ * milliseconds.
+ *
+ * @return float - power draw by the hub in stopped state
+ */
+ public float getStoppedPowerDrawMw() {
+ return mStoppedPowerDrawMw;
+ }
+
+ /**
+ * Set the power consumed by the hub in stopped state
+ *
+ * @param stoppedPowerDrawMw - stopped power in milli watts
+ */
+ public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
+ mStoppedPowerDrawMw = stoppedPowerDrawMw;
+ }
+
+ /**
+ * get the power draw of the hub in sleep mode. This assumes
+ * that the hub supports a sleep mode in which the power draw is
+ * lower than the power consumed when the hub is actively
+ * processing. As a guideline, assume that the hub should be
+ * able to enter sleep mode if it knows reliably on completion
+ * of some task that the next interrupt/scheduled work item is
+ * at least 250 milliseconds later.
+ *
+ * @return float - sleep power draw in milli watts
+ */
+ public float getSleepPowerDrawMw() {
+ return mSleepPowerDrawMw;
+ }
+
+ /**
+ * Set the sleep power draw in milliwatts
+ *
+ * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+ */
+ public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
+ mSleepPowerDrawMw = sleepPowerDrawMw;
+ }
+
+ /**
+ * get the peak powe draw of the hub. This is the power consumed
+ * by the hub at maximum load.
+ *
+ * @return float - peak power draw
+ */
+ public float getPeakPowerDrawMw() {
+ return mPeakPowerDrawMw;
+ }
+
+ /**
+ * set the peak power draw of the hub
+ *
+ * @param peakPowerDrawMw - peak power draw of the hub in
+ * milliwatts.
+ */
+ public void setPeakPowerDrawMw(float peakPowerDrawMw) {
+ mPeakPowerDrawMw = peakPowerDrawMw;
+ }
+
+ /**
+ * get the sensors supported by this hub
+ *
+ * @return int[] - all the supported sensors on this hub
+ *
+ * @see ContextHubManager
+ */
+ public int[] getSupportedSensors() {
+ return Arrays.copyOf(mSupportedSensors, mSupportedSensors.length);
+ }
+
+ /**
+ * get the various memory regions on this hub
+ *
+ * @return MemoryRegion[] - all the memory regions on this hub
+ *
+ * @see MemoryRegion
+ */
+ public MemoryRegion[] getMemoryRegions() {
+ return Arrays.copyOf(mMemoryRegions, mMemoryRegions.length);
+ }
+
+ /**
+ * set the supported sensors on this hub
+ *
+ * @param supportedSensors - supported sensors on this hub
+ */
+ public void setSupportedSensors(int[] supportedSensors) {
+ mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
+ }
+
+ /**
+ * set memory regions for this hub
+ *
+ * @param memoryRegions - memory regions information
+ *
+ * @see MemoryRegion
+ */
+ public void setMemoryRegions(MemoryRegion[] memoryRegions) {
+ mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
+ }
+
+ private ContextHubInfo(Parcel in) {
+ mId = in.readInt();
+ mName = in.readString();
+ mVendor = in.readString();
+ mToolchain = in.readString();
+ mPlatformVersion = in.readInt();
+ mToolchainVersion = in.readInt();
+ mStaticSwVersion = in.readInt();
+ mPeakMips = in.readFloat();
+ mStoppedPowerDrawMw = in.readFloat();
+ mSleepPowerDrawMw = in.readFloat();
+ mPeakPowerDrawMw = in.readFloat();
+
+ int numSupportedSensors = in.readInt();
+ mSupportedSensors = new int[numSupportedSensors];
+ in.readIntArray(mSupportedSensors);
+ mMemoryRegions = in.createTypedArray(MemoryRegion.CREATOR);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeString(mName);
+ out.writeString(mVendor);
+ out.writeString(mToolchain);
+ out.writeInt(mPlatformVersion);
+ out.writeInt(mToolchainVersion);
+ out.writeInt(mStaticSwVersion);
+ out.writeFloat(mPeakMips);
+ out.writeFloat(mStoppedPowerDrawMw);
+ out.writeFloat(mSleepPowerDrawMw);
+ out.writeFloat(mPeakPowerDrawMw);
+
+ out.writeInt(mSupportedSensors.length);
+ out.writeIntArray(mSupportedSensors);
+ out.writeTypedArray(mMemoryRegions, flags);
+ }
+
+ public static final Parcelable.Creator<ContextHubInfo> CREATOR
+ = new Parcelable.Creator<ContextHubInfo>() {
+ public ContextHubInfo createFromParcel(Parcel in) {
+ return new ContextHubInfo(in);
+ }
+
+ public ContextHubInfo[] newArray(int size) {
+ return new ContextHubInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
new file mode 100644
index 0000000..301b2e4
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.Manifest;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A class that exposes the Context hubs on a device to
+ * applicaions.
+ *
+ * Please not that this class is not expected to be used by
+ * unbundled applications. Also, calling applications are
+ * expected to have LOCTION_HARDWARE premissions to use this
+ * class.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContextHubManager {
+
+ private static final String TAG = "ContextHubManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+ private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+
+ private Context mContext;
+ private IContextHubService mContextHubService;
+ private boolean mContextHubConnected;
+
+ /**
+ * A special context hub identifer meaning any possible hub on
+ * the system.
+ */
+ public static final int ANY_HUB = -1;
+ /**
+ * A constant denoting a message to load a a Nano App
+ */
+ public static final int MSG_LOAD_NANO_APP = 1;
+ /**
+ * A constant denoting a message to unload a a Nano App
+ */
+ public static final int MSG_UNLOAD_NANO_APP = 2;
+ /**
+ * A constant denoting a message to send a message
+ */
+ public static final int MSG_DATA_SEND = 3;
+
+
+ /**
+ * Get a handle to all the context hubs in the system
+ * @return array of context hub handles
+ */
+ public int[] getContexthubHandles() {
+ int[] retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubHandles();
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub handles :" + e.toString());
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Get more information about a specific hub.
+ *
+ * @param contexthubHandle Handle of context hub
+ *
+ * @return ContextHubInfo returned information about the hub
+ *
+ * @see ContextHubInfo
+ */
+ public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+ ContextHubInfo retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubInfo(contexthubHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub info :" + e.toString());
+ }
+ }
+
+ return(retVal);
+ }
+
+ /**
+ * Load a nanoapp on a specified context hub
+ *
+ * @param hubHandle handle of context hub to load the app on.
+ * @param app the nanoApp to load on the hub
+ *
+ * @return int nanoAppInstance of the loaded nanoApp on success,
+ * -1 otherwise
+ *
+ * @see NanoApp
+ */
+ public int loadNanoApp(int hubHandle, NanoApp app) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.loadNanoApp(hubHandle, app);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch load nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Unload a specified nanoApp
+ *
+ * @param nanoAppInstanceHandle handle of the nanoApp to load
+ *
+ * @return int 0 on success, -1 otherewise
+ */
+ public int unloadNanoApp(int nanoAppInstanceHandle) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * get information about the nano app instance
+ *
+ * @param nanoAppInstanceHandle handle of the nanoAppInstance
+ *
+ * @return NanoAppInstanceInfo Inforamtion about the nano app
+ * instance.
+ *
+ * @see NanoAppInstanceInfo
+ */
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+ NanoAppInstanceInfo retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Find a specified nano app on the system
+ *
+ * @param hubHandle handle of hub to search for nano app
+ * @param filter filter specifying the search criteria for app
+ *
+ * @see NanoAppFilter
+ *
+ * @return Integer[] Array of handles to any found nano apps
+ */
+ public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+ int[] temp;
+ Integer[] retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ temp = mContextHubService.findNanoAppOnHub(hubHandle, filter);
+ retVal = new Integer[temp.length];
+ for (int i = 0; i < temp.length; i++) {
+ retVal[i] = temp[i];
+ }
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not query nanoApp instance :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Send a message to a spcific nano app instance on a context
+ * hub
+ *
+ *
+ * @param hubHandle handle of the hub to send the message to
+ * @param nanoAppHandle handle of the nano app to send to
+ * @param msg Message to be sent
+ *
+ * @see ContextHubMessage
+ *
+ * @return int 0 on success, -1 otherwise
+ */
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.sendMessage(hubHandle, nanoAppHandle, msg);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch send message :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ }
+
+ private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
+ @Override
+ public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
+
+ }
+ };
+
+ private ContextHubManager(Context context) {
+ checkPermissions();
+ mContext = context;
+ mContextHubConnected = false;
+ }
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mContextHubService = IContextHubService.Stub.asInterface(service);
+ mContextHubConnected = true;
+
+ // Register our Callback
+ try {
+ mContextHubService.registerCallBack(mClientCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not register callback with context hub service :" + e.toString());
+ }
+ Log.d(TAG, "contexthub manager connected to " + name.toString());
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mContextHubService = null;
+ mContextHubConnected = false;
+ Log.d(TAG, "contexthub manager disconnected from " + name.toString());
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
new file mode 100644
index 0000000..915f1ec
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubMessage;
+
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
new file mode 100644
index 0000000..954e97d
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubMessage {
+ private int mType;
+ private int mVersion;
+ private byte[]mData;
+
+ /**
+ * Get the message type
+ *
+ * @return int - message type
+ */
+ public int getMsgType() {
+ return mType;
+ }
+
+ /**
+ * get message version
+ *
+ * @return int - message version
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * get message data
+ *
+ * @return byte[] - message data buffer
+ */
+ public byte[] getData() {
+ return Arrays.copyOf(mData, mData.length);
+ }
+
+ /**
+ * set message type
+ *
+ * @param msgType - message type
+ */
+ public void setMsgType(int msgType) {
+ mType = msgType;
+ }
+
+ /**
+ * Set message version
+ *
+ * @param version - message version
+ */
+ public void setVersion(int version) {
+ mVersion = version;
+ }
+
+ /**
+ * set message data
+ *
+ * @param data - message buffer
+ */
+ public void setMsgData(byte[] data) {
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ /**
+ * Constructor for a context hub message
+ *
+ * @param msgType - message type
+ * @param version - version
+ * @param data - message buffer
+ */
+ public ContextHubMessage(int msgType, int version, byte[] data) {
+ mType = msgType;
+ mVersion = version;
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ private ContextHubMessage(Parcel in) {
+ mType = in.readInt();
+ mVersion = in.readInt();
+ byte[] byteBuffer = new byte[in.readInt()];
+ in.readByteArray(byteBuffer);
+ }
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mType);
+ out.writeInt(mVersion);
+ out.writeInt(mData.length);
+ out.writeByteArray(mData);
+ }
+
+ public static final Parcelable.Creator<ContextHubMessage> CREATOR
+ = new Parcelable.Creator<ContextHubMessage>() {
+ public ContextHubMessage createFromParcel(Parcel in) {
+ return new ContextHubMessage(in);
+ }
+
+ public ContextHubMessage[] newArray(int size) {
+ return new ContextHubMessage[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
new file mode 100644
index 0000000..a2a13c6
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class ContextHubService extends Service {
+
+ private static final String TAG = "ContextHubService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static ContextHubService sSingletonInstance;
+ private static final Object sSingletonInstanceLock = new Object();
+
+ private HashMap<Integer, ContextHubInfo> mHubHash;
+ private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
+ private ContextHubInfo[] mContexthubInfo;
+
+
+ private native int nativeSendMessage(int[] header, byte[] data);
+ private native ContextHubInfo[] nativeInitialize();
+
+ private int onMessageReceipt(int[] header, byte[] data) {
+ return 0;
+ }
+ private void initialize() {
+ mContexthubInfo = nativeInitialize();
+
+ mHubHash = new HashMap<Integer, ContextHubInfo>();
+
+ for (int i = 0; i < mContexthubInfo.length; i++) {
+ mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+ }
+ }
+
+ private ContextHubService(Context context) {
+ initialize();
+ Log.d(TAG, "Created from " + context.toString());
+ }
+
+ public static ContextHubService getInstance(Context context) {
+ synchronized (sSingletonInstanceLock) {
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new ContextHubService(context);
+ }
+ return sSingletonInstance;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+
+ private IContextHubCallback callback;
+
+ @Override
+ public int registerCallBack(IContextHubCallback callback) throws RemoteException{
+ this.callback = callback;
+ return 0;
+ }
+
+ @Override
+ public int[] getContextHubHandles() throws RemoteException {
+ int [] returnArray = new int[mHubHash.size()];
+ int i = 0;
+ for (int key : mHubHash.keySet()) {
+ // Add any filtering here
+ returnArray[i] = key;
+ i++;
+ }
+ return returnArray;
+ }
+
+ @Override
+ public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
+ return mHubHash.get(contexthubHandle);
+ }
+
+ @Override
+ public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
+ if (!mHubHash.containsKey(hubHandle)) {
+ return -1;
+ } else {
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
+ msgHeader[1] = app.getAppId();
+ msgHeader[2] = app.getAppVersion();
+ msgHeader[3] = 0; // LOADING_HINTS
+ msgHeader[4] = hubHandle;
+
+ int handle = nativeSendMessage(msgHeader, app.getAppBinary());
+
+ // if successful, add an entry to mNanoAppHash
+
+ if(handle > 0) {
+ return 0;
+ } else {
+
+ return -1;
+ }
+ }
+ }
+
+ @Override
+ public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return -1;
+ } else {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
+ msgHeader[1] = info.getContexthubId();
+ msgHeader[2] = info.getHandle();
+
+ int result = nativeSendMessage(msgHeader, null);
+ // if successful, remove the entry in mNanoAppHash
+ if(result == 0) {
+ mNanoAppHash.remove(nanoAppInstanceHandle);
+ }
+ return(result);
+ }
+ }
+
+ @Override
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+ // This assumes that all the nanoAppInfo is current. This is reasonable
+ // for the use cases for tightly controlled nanoApps.
+ //
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return(mNanoAppHash.get(nanoAppInstanceHandle));
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+ ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+ for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+ if(filter.testMatch(info)){
+ foundInstances.add(nanoAppInstance);
+ }
+ }
+
+ int[] retArray = new int[foundInstances.size()];
+ for (int i = 0; i < foundInstances.size(); i++) {
+ retArray[i] = foundInstances.get(i).intValue();
+ }
+
+ return retArray;
+ }
+
+ @Override
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
+ msgHeader[1] = hubHandle;
+ msgHeader[2] = nanoAppHandle;
+ msgHeader[3] = msg.getMsgType();
+ msgHeader[4] = msg.getVersion();
+
+ return (nativeSendMessage(msgHeader, msg.getData()));
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
new file mode 100644
index 0000000..45b1ef4
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.ContextHubMessage;
+
+/** @hide */
+oneway interface IContextHubCallback {
+ void onMessageReceipt(int hubId, int nanoAppId, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
new file mode 100644
index 0000000..b2db0b2
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+// Declare any non-default types here with import statements
+import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubCallback;
+
+/** @hide */
+interface IContextHubService {
+
+ // register a callback to receive messages
+ int registerCallBack(in IContextHubCallback callback);
+
+ // Gets a list of available context hub handles
+ int[] getContextHubHandles();
+
+ // Get the properties of a hub
+ ContextHubInfo getContextHubInfo(int contextHubHandle);
+
+ // Load a nanoapp on a specified context hub
+ int loadNanoApp(int hubHandle, in NanoApp app);
+
+ // Unload a nanoapp instance
+ int unloadNanoApp(int nanoAppInstanceHandle);
+
+ // get information about a nanoAppInstance
+ NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
+
+ // find all nanoApp instances matching some filter
+ int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
+
+ // send a message to a nanoApp
+ int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
new file mode 100644
index 0000000..e8c7615
--- /dev/null
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+
+@SystemApi
+public class MemoryRegion implements Parcelable{
+
+ private int mSizeBytes;
+ private int mSizeBytesFree;
+ private boolean mIsReadable;
+ private boolean mIsWritable;
+ private boolean mIsExecutable;
+
+ /**
+ * get the capacity of the memory region in bytes
+ *
+ * @return int - the memory capacity in bytes
+ */
+ public int getCapacityBytes() {
+ return mSizeBytes;
+ }
+
+ /**
+ * get the free capacity of the memory region in bytes
+ *
+ * @return int - free bytes
+ */
+ public int getFreeCapacityBytes() {
+ return mSizeBytesFree;
+ }
+
+ /**
+ * Is the memory readable
+ *
+ * @return boolean - true if memory is readable, false otherwise
+ */
+ public boolean isReadable() {
+ return mIsReadable;
+ }
+
+ /**
+ * Is the memory writable
+ *
+ * @return boolean - true if memory is writable, false otherwise
+ */
+ public boolean isWritable() {
+ return mIsWritable;
+ }
+
+ /**
+ * Is the memory executable
+ *
+ * @return boolean - true if memory is executable, false
+ * otherwise
+ */
+ public boolean isExecutable() {
+ return mIsExecutable;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSizeBytes);
+ dest.writeInt(mSizeBytesFree);
+ dest.writeInt(mIsReadable ? 1 : 0);
+ dest.writeInt(mIsWritable ? 1 : 0);
+ dest.writeInt(mIsExecutable ? 1 : 0);
+ }
+
+ public MemoryRegion(Parcel source) {
+ mSizeBytes = source.readInt();
+ mSizeBytesFree = source.readInt();
+ mIsReadable = source.readInt() != 0;
+ mIsWritable = source.readInt() != 0;
+ mIsExecutable = source.readInt() != 0;
+ }
+
+ public static final Parcelable.Creator<MemoryRegion> CREATOR
+ = new Parcelable.Creator<MemoryRegion>() {
+ public MemoryRegion createFromParcel(Parcel in) {
+ return new MemoryRegion(in);
+ }
+
+ public MemoryRegion[] newArray(int size) {
+ return new MemoryRegion[size];
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
new file mode 100644
index 0000000..d32c44a
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
new file mode 100644
index 0000000..36d181f
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class describing nano apps.
+ * A nano app is a piece of executable code that can be
+ * downloaded onto a specific architecture. These are targtted
+ * for low power compute domains on a device.
+ *
+ * Nano apps are expected to be used only by bundled apps only
+ * at this time.
+ *
+ * @hide
+ */
+@SystemApi
+public class NanoApp {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+ private byte[] mAppBinary;
+
+ public NanoApp() {
+ }
+
+ /**
+ * Set the publisher name
+ *
+ * @param publisher name of the publisher of this nano app
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * set the app identifier
+ *
+ * @param appId add identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the app version
+ *
+ * @param appVersion app version
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * set memory needed as read only
+ *
+ * @param neededReadMemBytes
+ * read only memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * set writable memory needed in bytes
+ *
+ * @param neededWriteMemBytes
+ * writable memory needed in bytes
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * set executable memory needed
+ *
+ * @param neededExecMemBytes
+ * executable memory needed in bytes
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * set the sensors needed for this app
+ *
+ * @param neededSensors
+ * needed Sensors
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * set output events returned by the nano app
+ *
+ * @param appBinary generated events
+ */
+ public void setAppBinary(byte[] appBinary) {
+ mAppBinary = appBinary;
+ }
+
+
+ /**
+ * get the publisher name
+ *
+ * @return publisher name
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return app name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * get the identifier of the app
+ *
+ * @return identifier for this app
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * get the app version
+ *
+ * @return app version
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * get the ammount of readable memory needed by this app
+ *
+ * @return readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * get the ammount og writable memory needed in bytes
+ *
+ * @return writable memory needed in bytes
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * executable memory needed in bytes
+ *
+ * @return executable memory needed in bytes
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * get the sensors needed by this app
+ *
+ * @return sensors needed
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return generated events
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * get the binary for this app
+ *
+ * @return app binary
+ */
+ public byte[] getAppBinary() {
+ return mAppBinary;
+ }
+
+ private NanoApp(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+
+ int binaryLength = in.readInt();
+ mAppBinary = new byte[binaryLength];
+ in.readByteArray(mAppBinary);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ out.writeInt(mAppBinary.length);
+ out.writeByteArray(mAppBinary);
+ }
+
+ public static final Parcelable.Creator<NanoApp> CREATOR
+ = new Parcelable.Creator<NanoApp>() {
+ public NanoApp createFromParcel(Parcel in) {
+ return new NanoApp(in);
+ }
+
+ public NanoApp[] newArray(int size) {
+ return new NanoApp[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
new file mode 100644
index 0000000..cc6d475
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
new file mode 100644
index 0000000..ac341e4
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppFilter {
+
+ // The appId, can be set to APP_ID_ANY
+ private long mAppId;
+
+ // Version to filter apps
+ private int mAppVersion;
+
+ // filtering spec for version
+ private int mVersionRestrictionMask;
+
+ // If APP_ID is any, then a match is performef with the vendor mask
+ private long mAppIdVendorMask;
+
+ // Id of the context hub this instance is expected on
+ private int mContextHubId;
+
+ /**
+ * Flag indicating any version. With this flag set, all versions shall match provided version.
+ */
+ public static final int FLAGS_VERSION_ANY = -1;
+ /**
+ * If this flag is set, only versions strictly greater than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_GREAT_THAN = 2;
+ /**
+ * If this flag is set, only versions strictly less than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_LESS_THAN = 4;
+ public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
+
+ /**
+ * If this flag is set, only versions strictly equal to the version specified shall match.
+ */
+ public static final int APP_ANY = -1;
+
+ /**
+ * If this flag is set, all vendors shall match.
+ */
+ public static final int VENDOR_ANY = -1;
+
+ /**
+ * If this flag is set, any hub shall match.
+ */
+ public static final int HUB_ANY = -1;
+
+ private NanoAppFilter(Parcel in) {
+ mAppId = in.readLong();
+ mAppVersion = in.readInt();
+ mVersionRestrictionMask = in.readInt();
+ mAppIdVendorMask = in.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+
+ out.writeLong(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mVersionRestrictionMask);
+ out.writeLong(mAppIdVendorMask);
+ }
+
+ /**
+ * Create a filter
+ *
+ * @param appId application id
+ * @param appVersion application version
+ * @param versionMask version
+ * @param vendorMask vendor
+ */
+ public NanoAppFilter(long appId, int appVersion, int versionMask, long vendorMask) {
+ mAppId = appId;
+ mAppVersion = appVersion;
+ mVersionRestrictionMask = versionMask;
+ mAppIdVendorMask = vendorMask;
+ }
+
+ private boolean versionsMatch(int versionRestrictionMask, int expected, int actual){
+ // some refactoring of version restriction mask is needed, until then, return all
+ return true;
+ }
+ /**
+ *
+ * @param nano app instance info
+ *
+ * @return true if this is a match, false otherwise
+ */
+ public boolean testMatch(NanoAppInstanceInfo info) {
+ if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+ (mAppId == APP_ANY || info.getAppId() == mAppId) &&
+ // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
+ (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static final Parcelable.Creator<NanoAppFilter> CREATOR
+ = new Parcelable.Creator<NanoAppFilter>() {
+ public NanoAppFilter createFromParcel(Parcel in) {
+ return new NanoAppFilter(in);
+ }
+
+ public NanoAppFilter[] newArray(int size) {
+ return new NanoAppFilter[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
new file mode 100644
index 0000000..c8c40d7
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppInstanceInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
new file mode 100644
index 0000000..ac62919
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppInstanceInfo {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+
+ private int mContexthubId;
+ private int mHandle;
+
+ public NanoAppInstanceInfo() {
+ }
+
+ /**
+ * get the publisher of this app
+ *
+ * @return String - name of the publisher
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+
+ /**
+ * set the publisher name for the app
+ *
+ * @param publisher - name of the publisher
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return String - name of the app
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name - name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * Get the application identifier
+ *
+ * @return int - application identifier
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * Set the application identifier
+ *
+ * @param appId - application identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @return int - version of the app
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @param appVersion - version of the app
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * Get the read memory needed by the app
+ *
+ * @return int - readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * Set the read memory needed by the app
+ *
+ * @param neededReadMemBytes - readable Memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * get writable memory needed by the app
+ *
+ * @return int - writable memory needed by the app
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * set writable memory needed by the app
+ *
+ * @param neededWriteMemBytes - writable memory needed by the
+ * app
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * get executable memory needed by the app
+ *
+ * @return int - executable memory needed by the app
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * set executable memory needed by the app
+ *
+ * @param neededExecMemBytes - executable memory needed by the
+ * app
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * Get the sensors needed by this app
+ *
+ * @return int[] all the required sensors needed by this app
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * set the sensors needed by this app
+ *
+ * @param neededSensors - all the sensors needed by this app
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return all the events that can be generated by this app
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * set the output events that can be generated by this app
+ *
+ * @param outputEvents - the events that may be generated by
+ * this app
+ */
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * get the context hub identifier
+ *
+ * @return int - system unique hub identifier
+ */
+ public int getContexthubId() {
+ return mContexthubId;
+ }
+
+ /**
+ * set the context hub identifier
+ *
+ * @param contexthubId - system wide unique identifier
+ */
+ public void setContexthubId(int contexthubId) {
+ mContexthubId = contexthubId;
+ }
+
+ /**
+ * get a handle to the nano app instance
+ *
+ * @return int - handle to this instance
+ */
+ public int getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * set the handle for an app instance
+ *
+ * @param handle - handle to this instance
+ */
+ public void setHandle(int handle) {
+ mHandle = handle;
+ }
+
+
+ private NanoAppInstanceInfo(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mContexthubId);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ }
+
+ public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
+ = new Parcelable.Creator<NanoAppInstanceInfo>() {
+ public NanoAppInstanceInfo createFromParcel(Parcel in) {
+ return new NanoAppInstanceInfo(in);
+ }
+
+ public NanoAppInstanceInfo[] newArray(int size) {
+ return new NanoAppInstanceInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 2f6dbe7..597efa5 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -25,9 +25,12 @@
/**
* Called when the keyphrase is spoken.
*
- * @param data Optional trigger audio data, if it was requested and is available.
+ * @param recognitionEvent Object containing data relating to the
+ * recognition event such as trigger audio data, if it was requested
+ * and is available.
*/
- void onDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
+ void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
+
/**
* Called when the detection fails due to an error.
*
@@ -42,4 +45,4 @@
* Called when the recognition is resumed after it was temporarily paused.
*/
void onRecognitionResumed();
-}
\ No newline at end of file
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index e16ea71..fec64ea 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -18,8 +18,11 @@
parcelable SoundTrigger.ConfidenceLevel;
parcelable SoundTrigger.Keyphrase;
+parcelable SoundTrigger.RecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionEvent;
+parcelable SoundTrigger.GenericSoundRecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionExtra;
parcelable SoundTrigger.KeyphraseSoundModel;
+parcelable SoundTrigger.GenericSoundModel;
parcelable SoundTrigger.ModuleProperties;
parcelable SoundTrigger.RecognitionConfig;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index d490409..882908a 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -195,6 +195,12 @@
/** Keyphrase sound model */
public static final int TYPE_KEYPHRASE = 0;
+ /**
+ * A generic sound model. Use this type only for non-keyphrase sound models such as
+ * ones that match a particular sound pattern.
+ */
+ public static final int TYPE_GENERIC_SOUND = 1;
+
/** Unique sound model identifier */
public final UUID uuid;
@@ -458,6 +464,63 @@
}
}
+
+ /*****************************************************************************
+ * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
+ * patterns.
+ ****************************************************************************/
+ public static class GenericSoundModel extends SoundModel implements Parcelable {
+
+ public static final Parcelable.Creator<GenericSoundModel> CREATOR
+ = new Parcelable.Creator<GenericSoundModel>() {
+ public GenericSoundModel createFromParcel(Parcel in) {
+ return GenericSoundModel.fromParcel(in);
+ }
+
+ public GenericSoundModel[] newArray(int size) {
+ return new GenericSoundModel[size];
+ }
+ };
+
+ public GenericSoundModel(UUID uuid, UUID vendorUuid, byte[] data) {
+ super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private static GenericSoundModel fromParcel(Parcel in) {
+ UUID uuid = UUID.fromString(in.readString());
+ UUID vendorUuid = null;
+ int length = in.readInt();
+ if (length >= 0) {
+ vendorUuid = UUID.fromString(in.readString());
+ }
+ byte[] data = in.readBlob();
+ return new GenericSoundModel(uuid, vendorUuid, data);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(uuid.toString());
+ if (vendorUuid == null) {
+ dest.writeInt(-1);
+ } else {
+ dest.writeInt(vendorUuid.toString().length());
+ dest.writeString(vendorUuid.toString());
+ }
+ dest.writeBlob(data);
+ }
+
+ @Override
+ public String toString() {
+ return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
+ + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
+ }
+ }
+
/**
* Modes for key phrase recognition
*/
@@ -1019,6 +1082,21 @@
}
/**
+ * Sub-class of RecognitionEvent specifically for sound-trigger based sound
+ * models(non-keyphrase). Currently does not contain any additional fields.
+ */
+ public static class GenericRecognitionEvent extends RecognitionEvent {
+ public GenericRecognitionEvent(int status, int soundModelHandle,
+ boolean captureAvailable, int captureSession, int captureDelayMs,
+ int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat,
+ byte[] data) {
+ super(status, soundModelHandle, captureAvailable, captureSession,
+ captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
+ data);
+ }
+ }
+
+ /**
* Status codes for {@link SoundModelEvent}
*/
/** Sound Model was updated */
@@ -1118,7 +1196,7 @@
public static final int SERVICE_STATE_DISABLED = 1;
/**
- * Returns a list of descriptors for all harware modules loaded.
+ * Returns a list of descriptors for all hardware modules loaded.
* @param modules A ModuleProperties array where the list will be returned.
* @return - {@link #STATUS_OK} in case of success
* - {@link #STATUS_ERROR} in case of unspecified error
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 92c721b..25b38c0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1189,7 +1189,7 @@
return TYPE_NONE;
}
- // Do this only for SUPL, until GpsLocationProvider is fixed. http://b/25876485 .
+ // Do this only for SUPL, until GnssLocationProvider is fixed. http://b/25876485 .
if (!netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
// NOTE: if this causes app breakage, we should not just comment out this early return;
// instead, we should make this early return conditional on the requesting app's target
@@ -3170,7 +3170,7 @@
// Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature,
// stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException.
- // TODO: convert the existing system users (Tethering, GpsLocationProvider) to the new APIs and
+ // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and
// remove these exemptions. Note that this check is not secure, and apps can still access these
// functions by accessing ConnectivityService directly. However, it should be clear that doing
// so is unsupported and may break in the future. http://b/22728205
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 3bd12c0..e27c0fb 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -197,6 +197,19 @@
(1 << NET_CAPABILITY_CAPTIVE_PORTAL);
/**
+ * Network specifier for factories which want to match any network specifier
+ * (NS) in a request. Behavior:
+ * <li>Empty NS in request matches any network factory NS</li>
+ * <li>Empty NS in the network factory NS only matches a request with an
+ * empty NS</li>
+ * <li>"*" (this constant) NS in the network factory matches requests with
+ * any NS</li>
+ *
+ * @hide
+ */
+ public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*";
+
+ /**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
* NetworkFactory / NetworkAgent model does not deal well with the situation where a
* capability's presence cannot be known in advance. If such a capability is requested, then we
@@ -596,7 +609,8 @@
}
private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
return (TextUtils.isEmpty(mNetworkSpecifier) ||
- mNetworkSpecifier.equals(nc.mNetworkSpecifier));
+ mNetworkSpecifier.equals(nc.mNetworkSpecifier) ||
+ MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier));
}
private boolean equalsSpecifier(NetworkCapabilities nc) {
if (TextUtils.isEmpty(mNetworkSpecifier)) {
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 7da4818..f1edcbe 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -188,6 +188,10 @@
* networks.
*/
public Builder setNetworkSpecifier(String networkSpecifier) {
+ if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) {
+ throw new IllegalArgumentException("Invalid network specifier - must not be '"
+ + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+ }
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
return this;
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 4a8dfbc..53b027b 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -2343,7 +2343,7 @@
*/
public void checkFileUriExposed(String location) {
if ("file".equals(getScheme())) {
- StrictMode.onFileUriExposed(location);
+ StrictMode.onFileUriExposed(this, location);
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9180506..52fa2ed 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -201,9 +201,14 @@
private static final String BATTERY_LEVEL_DATA = "lv";
private static final String GLOBAL_WIFI_DATA = "gwfl";
private static final String WIFI_DATA = "wfl";
- private static final String GLOBAL_BLUETOOTH_DATA = "gble";
+ private static final String GLOBAL_WIFI_CONTROLLER_DATA = "gwfcd";
+ private static final String WIFI_CONTROLLER_DATA = "wfcd";
+ private static final String GLOBAL_BLUETOOTH_CONTROLLER_DATA = "gble";
+ private static final String BLUETOOTH_CONTROLLER_DATA = "ble";
private static final String MISC_DATA = "m";
private static final String GLOBAL_NETWORK_DATA = "gn";
+ private static final String GLOBAL_MODEM_CONTROLLER_DATA = "gmcd";
+ private static final String MODEM_CONTROLLER_DATA = "mcd";
private static final String HISTORY_STRING_POOL = "hsp";
private static final String HISTORY_DATA = "h";
private static final String SCREEN_BRIGHTNESS_DATA = "br";
@@ -271,6 +276,39 @@
}
/**
+ * Container class that aggregates counters for transmit, receive, and idle state of a
+ * radio controller.
+ */
+ public static abstract class ControllerActivityCounter {
+ /**
+ * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
+ * idle state.
+ */
+ public abstract LongCounter getIdleTimeCounter();
+
+ /**
+ * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
+ * receive state.
+ */
+ public abstract LongCounter getRxTimeCounter();
+
+ /**
+ * An array of {@link LongCounter}, representing various transmit levels, where each level
+ * may draw a different amount of power. The levels themselves are controller-specific.
+ * @return non-null array of {@link LongCounter}s representing time spent (milliseconds) in
+ * various transmit level states.
+ */
+ public abstract LongCounter[] getTxTimeCounters();
+
+ /**
+ * @return a non-null {@link LongCounter} representing the power consumed by the controller
+ * in all states, measured in milli-ampere-milliseconds (mAms). The counter may always
+ * yield a value of 0 if the device doesn't support power calculations.
+ */
+ public abstract LongCounter getPowerCounter();
+ }
+
+ /**
* State for keeping track of timing information.
*/
public static abstract class Timer {
@@ -367,25 +405,9 @@
*/
public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
- /**
- * Returns the time in milliseconds that this app kept the WiFi controller in the
- * specified state <code>type</code>.
- * @param type one of {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, or
- * {@link #CONTROLLER_TX_TIME}.
- * @param which one of {@link #STATS_CURRENT}, {@link #STATS_SINCE_CHARGED}, or
- * {@link #STATS_SINCE_UNPLUGGED}.
- */
- public abstract long getWifiControllerActivity(int type, int which);
-
- /**
- * Returns the time in milliseconds that this app kept the Bluetooth controller in the
- * specified state <code>type</code>.
- * @param type one of {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, or
- * {@link #CONTROLLER_TX_TIME}.
- * @param which one of {@link #STATS_CURRENT}, {@link #STATS_SINCE_CHARGED}, or
- * {@link #STATS_SINCE_UNPLUGGED}.
- */
- public abstract long getBluetoothControllerActivity(int type, int which);
+ public abstract ControllerActivityCounter getWifiControllerActivity();
+ public abstract ControllerActivityCounter getBluetoothControllerActivity();
+ public abstract ControllerActivityCounter getModemControllerActivity();
/**
* {@hide}
@@ -2031,43 +2053,47 @@
public abstract long getNetworkActivityBytes(int type, int which);
public abstract long getNetworkActivityPackets(int type, int which);
- public static final int CONTROLLER_IDLE_TIME = 0;
- public static final int CONTROLLER_RX_TIME = 1;
- public static final int CONTROLLER_TX_TIME = 2;
- public static final int CONTROLLER_POWER_DRAIN = 3;
- public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_POWER_DRAIN + 1;
-
- /**
- * Returns true if the BatteryStats object has detailed bluetooth power reports.
- * When true, calling {@link #getBluetoothControllerActivity(int, int)} will yield the
- * actual power data.
- */
- public abstract boolean hasBluetoothActivityReporting();
-
- /**
- * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
- * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
- * respective state.
- * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
- * milli-ampere-milliseconds (mAms).
- */
- public abstract long getBluetoothControllerActivity(int type, int which);
-
/**
* Returns true if the BatteryStats object has detailed WiFi power reports.
- * When true, calling {@link #getWifiControllerActivity(int, int)} will yield the
+ * When true, calling {@link #getWifiControllerActivity()} will yield the
* actual power data.
*/
public abstract boolean hasWifiActivityReporting();
/**
- * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
- * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
- * respective state.
- * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
- * milli-ampere-milliseconds (mAms).
+ * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+ * in various radio controller states, such as transmit, receive, and idle.
+ * @return non-null {@link ControllerActivityCounter}
*/
- public abstract long getWifiControllerActivity(int type, int which);
+ public abstract ControllerActivityCounter getWifiControllerActivity();
+
+ /**
+ * Returns true if the BatteryStats object has detailed bluetooth power reports.
+ * When true, calling {@link #getBluetoothControllerActivity()} will yield the
+ * actual power data.
+ */
+ public abstract boolean hasBluetoothActivityReporting();
+
+ /**
+ * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+ * in various radio controller states, such as transmit, receive, and idle.
+ * @return non-null {@link ControllerActivityCounter}
+ */
+ public abstract ControllerActivityCounter getBluetoothControllerActivity();
+
+ /**
+ * Returns true if the BatteryStats object has detailed modem power reports.
+ * When true, calling {@link #getModemControllerActivity()} will yield the
+ * actual power data.
+ */
+ public abstract boolean hasModemActivityReporting();
+
+ /**
+ * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+ * in various radio controller states, such as transmit, receive, and idle.
+ * @return non-null {@link ControllerActivityCounter}
+ */
+ public abstract ControllerActivityCounter getModemControllerActivity();
/**
* Return the wall clock time when battery stats data collection started.
@@ -2496,6 +2522,17 @@
return ",";
}
+ private static final void dumpLineHeader(PrintWriter pw, int uid, String category,
+ String type) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION);
+ pw.print(',');
+ pw.print(uid);
+ pw.print(',');
+ pw.print(category);
+ pw.print(',');
+ pw.print(type);
+ }
+
/**
* Dump a comma-separated line of values for terse checkin mode.
*
@@ -2506,14 +2543,7 @@
*/
private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
Object... args ) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION);
- pw.print(',');
- pw.print(uid);
- pw.print(',');
- pw.print(category);
- pw.print(',');
- pw.print(type);
-
+ dumpLineHeader(pw, uid, category, type);
for (Object arg : args) {
pw.print(',');
pw.print(arg);
@@ -2546,6 +2576,140 @@
}
/**
+ * Checks if the ControllerActivityCounter has any data worth dumping.
+ */
+ private static boolean controllerActivityHasData(ControllerActivityCounter counter, int which) {
+ if (counter == null) {
+ return false;
+ }
+
+ if (counter.getIdleTimeCounter().getCountLocked(which) != 0
+ || counter.getRxTimeCounter().getCountLocked(which) != 0
+ || counter.getPowerCounter().getCountLocked(which) != 0) {
+ return true;
+ }
+
+ for (LongCounter c : counter.getTxTimeCounters()) {
+ if (c.getCountLocked(which) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Dumps the ControllerActivityCounter if it has any data worth dumping.
+ * The order of the arguments in the final check in line is:
+ *
+ * idle, rx, power, tx...
+ *
+ * where tx... is one or more transmit level times.
+ */
+ private static final void dumpControllerActivityLine(PrintWriter pw, int uid, String category,
+ String type,
+ ControllerActivityCounter counter,
+ int which) {
+ if (!controllerActivityHasData(counter, which)) {
+ return;
+ }
+
+ dumpLineHeader(pw, uid, category, type);
+ pw.print(",");
+ pw.print(counter.getIdleTimeCounter().getCountLocked(which));
+ pw.print(",");
+ pw.print(counter.getRxTimeCounter().getCountLocked(which));
+ pw.print(",");
+ pw.print(counter.getPowerCounter().getCountLocked(which) / (1000 * 60 * 60));
+ for (LongCounter c : counter.getTxTimeCounters()) {
+ pw.print(",");
+ pw.print(c.getCountLocked(which));
+ }
+ pw.println();
+ }
+
+ private final void printControllerActivityIfInteresting(PrintWriter pw, StringBuilder sb,
+ String prefix, String controllerName,
+ ControllerActivityCounter counter,
+ int which) {
+ if (controllerActivityHasData(counter, which)) {
+ printControllerActivity(pw, sb, prefix, controllerName, counter, which);
+ }
+ }
+
+ private final void printControllerActivity(PrintWriter pw, StringBuilder sb, String prefix,
+ String controllerName,
+ ControllerActivityCounter counter, int which) {
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
+ final long powerDrainMaMs = counter.getPowerCounter().getCountLocked(which);
+ long totalTxTimeMs = 0;
+ for (LongCounter txState : counter.getTxTimeCounters()) {
+ totalTxTimeMs += txState.getCountLocked(which);
+ }
+
+ final long totalTimeMs = idleTimeMs + rxTimeMs + totalTxTimeMs;
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(controllerName);
+ sb.append(" Idle time: ");
+ formatTimeMs(sb, idleTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(idleTimeMs, totalTimeMs));
+ sb.append(")");
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(controllerName);
+ sb.append(" Rx time: ");
+ formatTimeMs(sb, rxTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(rxTimeMs, totalTimeMs));
+ sb.append(")");
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(controllerName);
+ sb.append(" Tx time: ");
+ formatTimeMs(sb, totalTxTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(totalTxTimeMs, totalTimeMs));
+ sb.append(")");
+ pw.println(sb.toString());
+
+ final int numTxLvls = counter.getTxTimeCounters().length;
+ if (numTxLvls > 1) {
+ for (int lvl = 0; lvl < numTxLvls; lvl++) {
+ final long txLvlTimeMs = counter.getTxTimeCounters()[lvl].getCountLocked(which);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" [");
+ sb.append(lvl);
+ sb.append("] ");
+ formatTimeMs(sb, txLvlTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(txLvlTimeMs, totalTxTimeMs));
+ sb.append(")");
+ pw.println(sb.toString());
+ }
+ }
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(controllerName);
+ sb.append(" Power drain: ").append(
+ BatteryStatsHelper.makemAh(powerDrainMaMs / (double) (1000*60*60)));
+ sb.append("mAh");
+ pw.println(sb.toString());
+ }
+
+ /**
* Temporary for settings.
*/
public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) {
@@ -2637,24 +2801,22 @@
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets);
+ // Dump Modem controller stats
+ dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_MODEM_CONTROLLER_DATA,
+ getModemControllerActivity(), which);
+
// Dump Wifi controller stats
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, 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 wifiPowerMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
- dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA,
- wifiOnTime / 1000, wifiRunningTime / 1000,
- wifiIdleTimeMs, wifiRxTimeMs, wifiTxTimeMs, wifiPowerMaMs / (1000*60*60));
+ dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA, wifiOnTime / 1000,
+ wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+
+ dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_WIFI_CONTROLLER_DATA,
+ getWifiControllerActivity(), which);
// Dump Bluetooth controller stats
- final long btIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long btRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
- final long btTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
- final long btPowerMaMs = getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which);
- dumpLine(pw, 0 /* uid */, category, GLOBAL_BLUETOOTH_DATA,
- btIdleTimeMs, btRxTimeMs, btTxTimeMs, btPowerMaMs / (1000*60*60));
+ dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_BLUETOOTH_CONTROLLER_DATA,
+ getBluetoothControllerActivity(), which);
// Dump misc stats
dumpLine(pw, 0 /* uid */, category, MISC_DATA,
@@ -2865,21 +3027,25 @@
mobileActiveTime, mobileActiveCount);
}
+ // Dump modem controller data, per UID.
+ dumpControllerActivityLine(pw, uid, category, MODEM_CONTROLLER_DATA,
+ u.getModemControllerActivity(), which);
+
+ // Dump Wifi controller data, per UID.
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);
- final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
- final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
- || uidWifiRunningTime != 0 || uidWifiIdleTimeMs != 0 || uidWifiRxTimeMs != 0
- || uidWifiTxTimeMs != 0) {
- dumpLine(pw, uid, category, WIFI_DATA,
- fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount,
- uidWifiIdleTimeMs, uidWifiRxTimeMs, uidWifiTxTimeMs);
+ || uidWifiRunningTime != 0) {
+ dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
+ uidWifiRunningTime, wifiScanCount,
+ /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
}
+ dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
+ u.getWifiControllerActivity(), which);
+
if (u.hasUserActivity()) {
args = new Object[Uid.NUM_USER_ACTIVITY_TYPES];
boolean hasData = false;
@@ -3409,6 +3575,8 @@
pw.println(sb.toString());
}
+ printControllerActivity(pw, sb, prefix, "Radio", getModemControllerActivity(), which);
+
pw.print(prefix);
pw.print(" Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
@@ -3494,85 +3662,14 @@
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- 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 wifiPowerDrainMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
- final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" WiFi Rx time: "); formatTimeMs(sb, wifiRxTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" WiFi Tx time: "); formatTimeMs(sb, wifiTxTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" WiFi Power drain: ").append(
- BatteryStatsHelper.makemAh(wifiPowerDrainMaMs / (double) (1000*60*60)));
- sb.append("mAh");
- pw.println(sb.toString());
+ printControllerActivity(pw, sb, prefix, "WiFi", getWifiControllerActivity(), which);
pw.print(prefix);
pw.print(" Bluetooth total received: "); pw.print(formatBytesLocked(btRxTotalBytes));
pw.print(", sent: "); pw.println(formatBytesLocked(btTxTotalBytes));
- final long bluetoothIdleTimeMs =
- getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
- final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
- final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs +
- bluetoothTxTimeMs;
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth Rx time: "); formatTimeMs(sb, bluetoothRxTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth Tx time: "); formatTimeMs(sb, bluetoothTxTimeMs);
- sb.append("(");
- sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth Power drain: ").append(BatteryStatsHelper.makemAh(
- getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which) /
- (double)(1000*60*60)));
- sb.append("mAh");
- pw.println(sb.toString());
+ printControllerActivity(pw, sb, prefix, "Bluetooth", getBluetoothControllerActivity(),
+ which);
pw.println();
@@ -3897,6 +3994,9 @@
pw.println(sb.toString());
}
+ printControllerActivityIfInteresting(pw, sb, prefix + " ", "Modem",
+ u.getModemControllerActivity(), which);
+
if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) {
pw.print(prefix); pw.print(" Wi-Fi network: ");
pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, ");
@@ -3925,26 +4025,8 @@
pw.println(sb.toString());
}
- final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
- final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
- final long uidWifiTotalTimeMs = uidWifiIdleTimeMs + uidWifiRxTimeMs + uidWifiTxTimeMs;
- if (uidWifiTotalTimeMs > 0) {
- sb.setLength(0);
- sb.append(prefix).append(" WiFi Idle time: ");
- formatTimeMs(sb, uidWifiIdleTimeMs);
- sb.append("(").append(formatRatioLocked(uidWifiIdleTimeMs, uidWifiTotalTimeMs))
- .append(")\n");
-
- sb.append(prefix).append(" WiFi Rx time: "); formatTimeMs(sb, uidWifiRxTimeMs);
- sb.append("(").append(formatRatioLocked(uidWifiRxTimeMs, uidWifiTotalTimeMs))
- .append(")\n");
-
- sb.append(prefix).append(" WiFi Tx time: "); formatTimeMs(sb, uidWifiTxTimeMs);
- sb.append("(").append(formatRatioLocked(uidWifiTxTimeMs, uidWifiTotalTimeMs))
- .append(")");
- pw.println(sb.toString());
- }
+ printControllerActivityIfInteresting(pw, sb, prefix + " ", "WiFi",
+ u.getWifiControllerActivity(), which);
if (btRxBytes > 0 || btTxBytes > 0) {
pw.print(prefix); pw.print(" Bluetooth network: ");
@@ -3953,30 +4035,6 @@
pw.println(" sent");
}
- final long uidBtIdleTimeMs = u.getBluetoothControllerActivity(CONTROLLER_IDLE_TIME,
- which);
- final long uidBtRxTimeMs = u.getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
- final long uidBtTxTimeMs = u.getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
- final long uidBtTotalTimeMs = uidBtIdleTimeMs + uidBtRxTimeMs + uidBtTxTimeMs;
- if (uidBtTotalTimeMs > 0) {
- sb.setLength(0);
- sb.append(prefix).append(" Bluetooth Idle time: ");
- formatTimeMs(sb, uidBtIdleTimeMs);
- sb.append("(").append(formatRatioLocked(uidBtIdleTimeMs, uidBtTotalTimeMs))
- .append(")\n");
-
- sb.append(prefix).append(" Bluetooth Rx time: ");
- formatTimeMs(sb, uidBtRxTimeMs);
- sb.append("(").append(formatRatioLocked(uidBtRxTimeMs, uidBtTotalTimeMs))
- .append(")\n");
-
- sb.append(prefix).append(" Bluetooth Tx time: ");
- formatTimeMs(sb, uidBtTxTimeMs);
- sb.append("(").append(formatRatioLocked(uidBtTxTimeMs, uidBtTotalTimeMs))
- .append(")");
- pw.println(sb.toString());
- }
-
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 1af2034..d73deb6 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -468,6 +468,9 @@
/**
* Handle a call to {@link #shellCommand}. The default implementation simply prints
* an error message. Override and replace with your own.
+ * <p class="caution">Note: no permission checking is done before calling this method; you must
+ * apply any security checks as appropriate for the command being executed.
+ * Consider using {@link ShellCommand} to help in the implementation.</p>
* @hide
*/
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
diff --git a/core/java/android/os/FileUriExposedException.java b/core/java/android/os/FileUriExposedException.java
new file mode 100644
index 0000000..e47abe2
--- /dev/null
+++ b/core/java/android/os/FileUriExposedException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.Intent;
+
+/**
+ * The exception that is thrown when an application exposes a {@code file://}
+ * {@link android.net.Uri} to another app.
+ * <p>
+ * This exposure is discouraged since the receiving app may not have access to
+ * the shared path. For example, the receiving app may not have requested the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime permission,
+ * or the platform may be sharing the {@link android.net.Uri} across user
+ * profile boundaries.
+ * <p>
+ * Instead, apps should use {@code content://} Uris so the platform can extend
+ * temporary permission for the receiving app to access the resource.
+ * <p>
+ * This is only thrown for applications targeting {@link Build.VERSION_CODES#N}
+ * or higher. Applications targeting earlier SDK versions are allowed to share
+ * {@code file://} {@link android.net.Uri}, but it's strongly discouraged.
+ *
+ * @see android.support.v4.content.FileProvider
+ * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
+ */
+public class FileUriExposedException extends RuntimeException {
+ public FileUriExposedException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 4159d89..314b7d5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,6 +219,15 @@
public static final int DRAW_WAKE_LOCK = 0x00000080;
/**
+ * Wake lock level: Enables Sustained Performance Mode.
+ * <p>
+ * This is used by Gaming and VR applications to ensure the device provides
+ * will provide consistent performance over a large amount of time.
+ * </p>
+ */
+ public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
+
+ /**
* Mask for the wake lock level component of a combined wake lock level and flags integer.
*
* @hide
@@ -525,6 +534,7 @@
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
case DOZE_WAKE_LOCK:
case DRAW_WAKE_LOCK:
+ case SUSTAINED_PERFORMANCE_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index eca2c3b..1e4ee4b 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -150,6 +150,12 @@
public static final int AUDIOSERVER_UID = 1041;
/**
+ * Defines the UID/GID for the cameraserver process
+ * @hide
+ */
+ public static final int CAMERASERVER_UID = 1047;
+
+ /**
* Defines the start of a range of UIDs (and GIDs), going from this
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
* to applications.
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index 6f12b62..54d1090 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -24,9 +24,11 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
/**
+ * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}.
* @hide
*/
public abstract class ShellCommand {
@@ -44,6 +46,10 @@
private int mArgPos;
private String mCurArgData;
+ private FileInputStream mFileIn;
+ private FileOutputStream mFileOut;
+ private FileOutputStream mFileErr;
+
private FastPrintWriter mOutPrintWriter;
private FastPrintWriter mErrPrintWriter;
private InputStream mInputStream;
@@ -59,8 +65,12 @@
mCmd = null;
mArgPos = firstArgPos;
mCurArgData = null;
+ mFileIn = null;
+ mFileOut = null;
+ mFileErr = null;
mOutPrintWriter = null;
mErrPrintWriter = null;
+ mInputStream = null;
}
public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
@@ -112,28 +122,65 @@
return res;
}
+ /**
+ * Return direct raw access (not buffered) to the command's output data stream.
+ */
+ public OutputStream getRawOutputStream() {
+ if (mFileOut == null) {
+ mFileOut = new FileOutputStream(mOut);
+ }
+ return mFileOut;
+ }
+
+ /**
+ * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
+ */
public PrintWriter getOutPrintWriter() {
if (mOutPrintWriter == null) {
- FileOutputStream fout = new FileOutputStream(mOut);
- mOutPrintWriter = new FastPrintWriter(fout);
+ mOutPrintWriter = new FastPrintWriter(getRawOutputStream());
}
return mOutPrintWriter;
}
+ /**
+ * Return direct raw access (not buffered) to the command's error output data stream.
+ */
+ public OutputStream getRawErrorStream() {
+ if (mFileErr == null) {
+ mFileErr = new FileOutputStream(mErr);
+ }
+ return mFileErr;
+ }
+
+ /**
+ * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
+ */
public PrintWriter getErrPrintWriter() {
if (mErr == null) {
return getOutPrintWriter();
}
if (mErrPrintWriter == null) {
- FileOutputStream fout = new FileOutputStream(mErr);
- mErrPrintWriter = new FastPrintWriter(fout);
+ mErrPrintWriter = new FastPrintWriter(getRawErrorStream());
}
return mErrPrintWriter;
}
- public InputStream getInputStream() {
+ /**
+ * Return direct raw access (not buffered) to the command's input data stream.
+ */
+ public InputStream getRawInputStream() {
+ if (mFileIn == null) {
+ mFileIn = new FileInputStream(mIn);
+ }
+ return mFileIn;
+ }
+
+ /**
+ * Return buffered access to the command's {@link #getRawInputStream()}.
+ */
+ public InputStream getBufferedInputStream() {
if (mInputStream == null) {
- mInputStream = new BufferedInputStream(new FileInputStream(mIn));
+ mInputStream = new BufferedInputStream(getRawInputStream());
}
return mInputStream;
}
@@ -214,7 +261,28 @@
return -1;
}
+ /**
+ * Implement parsing and execution of a command. If it isn't a command you understand,
+ * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
+ * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
+ * to process additional command line arguments. Command output can be written to
+ * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
+ *
+ * <p class="caution">Note that no permission checking has been done before entering this function,
+ * so you need to be sure to do your own security verification for any commands you
+ * are executing. The easiest way to do this is to have the ShellCommand contain
+ * only a reference to your service's aidl interface, and do all of your command
+ * implementations on top of that -- that way you can rely entirely on your executing security
+ * code behind that interface.</p>
+ *
+ * @param cmd The first command line argument representing the name of the command to execute.
+ * @return Return the command result; generally 0 or positive indicates success and
+ * negative values indicate error.
+ */
public abstract int onCommand(String cmd);
+ /**
+ * Implement this to print help text about your command to {@link #getOutPrintWriter()}.
+ */
public abstract void onHelp();
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f1672df..91d88da 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Printer;
@@ -46,7 +47,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -243,42 +243,15 @@
// Byte 3: Penalty
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
-
- // Used for both process and thread policy:
-
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DIALOG = 0x02 << 16;
-
- /**
- * Death on any detected violation.
- *
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DEATH = 0x04 << 16;
-
- /**
- * Death just for detected network usage.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16;
-
- /**
- * Flash the screen during violations.
- *
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_FLASH = 0x10 << 16;
-
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DROPBOX = 0x20 << 16;
/**
@@ -294,12 +267,28 @@
*/
public static final int PENALTY_GATHER = 0x40 << 16;
+ // Byte 4: Special cases
+
+ /**
+ * Death when network traffic is detected on main thread.
+ *
+ * @hide
+ */
+ public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
+
/**
* Death when cleartext network traffic is detected.
*
* @hide
*/
- public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16;
+ public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
+
+ /**
+ * Death when file exposure is detected.
+ *
+ * @hide
+ */
+ public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
/**
* Mask of all the penalty bits valid for thread policies.
@@ -312,7 +301,7 @@
* Mask of all the penalty bits valid for VM policies.
*/
private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
- | PENALTY_DEATH_ON_CLEARTEXT_NETWORK;
+ | PENALTY_DEATH_ON_CLEARTEXT_NETWORK | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -748,10 +737,22 @@
}
/**
- * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this
- * app. The receiving app may not have access to the sent path.
- * Instead, when sharing files between apps, {@code content://}
- * should be used with permission grants.
+ * Detect when this application exposes a {@code file://}
+ * {@link android.net.Uri} to another app.
+ * <p>
+ * This exposure is discouraged since the receiving app may not have
+ * access to the shared path. For example, the receiving app may not
+ * have requested the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime
+ * permission, or the platform may be sharing the
+ * {@link android.net.Uri} across user profile boundaries.
+ * <p>
+ * Instead, apps should use {@code content://} Uris so the platform
+ * can extend temporary permission for the receiving app to access
+ * the resource.
+ *
+ * @see android.support.v4.content.FileProvider
+ * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public Builder detectFileUriExposure() {
return enable(DETECT_VM_FILE_URI_EXPOSURE);
@@ -798,6 +799,16 @@
}
/**
+ * Crashes the whole process when a {@code file://}
+ * {@link android.net.Uri} is exposed beyond this app.
+ *
+ * @see #detectFileUriExposure()
+ */
+ public Builder penaltyDeathOnFileUriExposure() {
+ return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+ }
+
+ /**
* Log detected violations to the system log.
*/
public Builder penaltyLog() {
@@ -1111,6 +1122,25 @@
}
/**
+ * Used by the framework to make file usage a fatal error.
+ *
+ * @hide
+ */
+ public static void enableDeathOnFileUriExposure() {
+ sVmPolicyMask |= DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+ }
+
+ /**
+ * Used by lame internal apps that haven't done the hard work to get
+ * themselves off file:// Uris yet.
+ *
+ * @hide
+ */
+ public static void disableDeathOnFileUriExposure() {
+ sVmPolicyMask &= ~(DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+ }
+
+ /**
* Parses the BlockGuard policy mask out from the Exception's
* getMessage() String value. Kinda gross, but least
* invasive. :/
@@ -1755,9 +1785,13 @@
/**
* @hide
*/
- public static void onFileUriExposed(String location) {
- final String message = "file:// Uri exposed through " + location;
- onVmPolicyViolation(null, new Throwable(message));
+ public static void onFileUriExposed(Uri uri, String location) {
+ final String message = uri + " exposed beyond app through " + location;
+ if ((sVmPolicyMask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
+ throw new FileUriExposedException(message);
+ } else {
+ onVmPolicyViolation(null, new Throwable(message));
+ }
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index bcc1213..344d06e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -144,6 +144,7 @@
}
/** @hide */
+ @SystemApi
public static UserHandle of(@UserIdInt int userId) {
return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fe834a1..1ac798b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -21,6 +21,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
+import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
@@ -621,6 +622,20 @@
/** @hide */
public static final int PIN_VERIFICATION_SUCCESS = -1;
+ /**
+ * Error result indicating that this user is not allowed to add other users on this device.
+ * This is a result code returned from the activity created by the intent
+ * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+ */
+ public static final int USER_CREATION_FAILED_NOT_PERMITTED = Activity.RESULT_FIRST_USER;
+
+ /**
+ * Error result indicating that no more users can be created on this device.
+ * This is a result code returned from the activity created by the intent
+ * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+ */
+ public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
+
/** @hide */
public static UserManager get(Context context) {
return (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -1194,7 +1209,10 @@
* If this device does not support multiple users, null is returned.
* <p/>
* The intent should be launched using startActivityForResult and the return result will
- * indicate if the user consented to adding a new user and if the operation succeeded.
+ * indicate if the user consented to adding a new user and if the operation succeeded. Any
+ * errors in creating the user will be returned in the result code. If the user cancels the
+ * request, the return result will be {@link Activity#RESULT_CANCELED}. On success, the
+ * result code will be {@link Activity#RESULT_OK}.
* <p/>
* The new user is created but not initialized. After switching into the user for the first
* time, the preferred user name and account information are used by the setup process for that
@@ -1211,6 +1229,8 @@
* Handler)}.
* @return An Intent that can be launched from an Activity or null if creating users is not
* supported on this device.
+ * @see #USER_CREATION_FAILED_NOT_PERMITTED
+ * @see #USER_CREATION_FAILED_NO_MORE_USERS
*/
public static Intent createUserCreationIntent(@Nullable String userName,
@Nullable String accountName,
@@ -1362,7 +1382,7 @@
/**
* Returns information for all users on this device.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @return the list of users that were created.
+ * @return the list of users that exist on the device.
* @hide
*/
public List<UserInfo> getUsers() {
@@ -1375,6 +1395,29 @@
}
/**
+ * Returns serial numbers of all users on this device.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @param excludeDying specify if the list should exclude users being removed.
+ * @return the list of serial numbers of users that exist on the device.
+ * @hide
+ */
+ @SystemApi
+ public long[] getSerialNumbersOfUsers(boolean excludeDying) {
+ try {
+ List<UserInfo> users = mService.getUsers(excludeDying);
+ long[] result = new long[users.size()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = users.get(i).serialNumber;
+ }
+ return result;
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get users list", re);
+ return null;
+ }
+ }
+
+ /**
* @return the user's account name, null if not found.
* @hide
*/
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index f765336..58a0269 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -91,4 +91,19 @@
* the icon is in this method.
*/
public abstract void setUserIcon(int userId, Bitmap bitmap);
+
+ /**
+ * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to inform the
+ * user manager whether all users should be created ephemeral.
+ */
+ public abstract void setForceEphemeralUsers(boolean forceEphemeralUsers);
+
+ /**
+ * Switches to the system user and deletes all other users.
+ *
+ * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
+ * the force-ephemeral-users policy is toggled on to make sure there are no pre-existing
+ * non-ephemeral users left.
+ */
+ public abstract void removeAllUsers();
}
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fda6326..ebb12fd 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.annotation.SystemApi;
import android.annotation.XmlRes;
import android.app.Activity;
import android.content.Context;
@@ -24,8 +25,8 @@
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
@@ -110,7 +111,13 @@
* managed by this instance.
*/
private int mSharedPreferencesMode;
-
+
+ private static final int STORAGE_DEFAULT = 0;
+ private static final int STORAGE_DEVICE_ENCRYPTED = 1;
+ private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
+
+ private int mStorage = STORAGE_DEFAULT;
+
/**
* The {@link PreferenceScreen} at the root of the preference hierarchy.
*/
@@ -343,6 +350,46 @@
}
/**
+ * Sets the storage location used internally by this class to be the default
+ * provided by the hosting {@link Context}.
+ */
+ public void setStorageDefault() {
+ mStorage = STORAGE_DEFAULT;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * device-encrypted storage.
+ * <p>
+ * Data stored in device-encrypted storage is typically encrypted with a key
+ * tied to the physical device, and it can be accessed when the device has
+ * booted successfully, both <em>before and after</em> the user has
+ * authenticated with their credentials (such as a lock pattern or PIN).
+ * Because device-encrypted data is available before user authentication,
+ * you should carefully consider what data you store using this mode.
+ *
+ * @see Context#createDeviceEncryptedStorageContext()
+ */
+ public void setStorageDeviceEncrypted() {
+ mStorage = STORAGE_DEVICE_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * credential-encrypted storage.
+ *
+ * @see Context#createCredentialEncryptedStorageContext()
+ * @hide
+ */
+ @SystemApi
+ public void setStorageCredentialEncrypted() {
+ mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
* Gets a SharedPreferences instance that preferences managed by this will
* use.
*
@@ -351,7 +398,20 @@
*/
public SharedPreferences getSharedPreferences() {
if (mSharedPreferences == null) {
- mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+ final Context storageContext;
+ switch (mStorage) {
+ case STORAGE_DEVICE_ENCRYPTED:
+ storageContext = mContext.createDeviceEncryptedStorageContext();
+ break;
+ case STORAGE_CREDENTIAL_ENCRYPTED:
+ storageContext = mContext.createCredentialEncryptedStorageContext();
+ break;
+ default:
+ storageContext = mContext;
+ break;
+ }
+
+ mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
mSharedPreferencesMode);
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index cdd88f6..032d83d 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -234,6 +234,9 @@
* @see #FLAG_DIR_PREFERS_LAST_MODIFIED
* @see #FLAG_VIRTUAL_DOCUMENT
* @see #FLAG_ARCHIVE
+ * @see #FLAG_SUPPORTS_COPY
+ * @see #FLAG_SUPPORTS_MOVE
+ * @see #FLAG_SUPPORTS_REMOVE
*/
public static final String COLUMN_FLAGS = "flags";
@@ -371,6 +374,15 @@
public static final int FLAG_ARCHIVE = 1 << 10;
/**
+ * Flag indicating that a document can be removed from a parent.
+ *
+ * @see #COLUMN_FLAGS
+ * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri)
+ * @see DocumentsProvider#removeDocument(String, String)
+ */
+ public static final int FLAG_SUPPORTS_REMOVE = 1 << 11;
+
+ /**
* Flag indicating that document titles should be hidden when viewing
* this directory in a larger format grid. For example, a directory
* containing only images may want the image thumbnails to speak for
@@ -612,6 +624,8 @@
public static final String METHOD_MOVE_DOCUMENT = "android:moveDocument";
/** {@hide} */
public static final String METHOD_IS_CHILD_DOCUMENT = "android:isChildDocument";
+ /** {@hide} */
+ public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument";
/** {@hide} */
public static final String EXTRA_PARENT_URI = "parentUri";
@@ -835,7 +849,12 @@
return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme());
}
- /** {@hide} */
+ /**
+ * Test if the given URI represents a {@link Document} tree.
+ *
+ * @see #buildTreeDocumentUri(String, String)
+ * @see #getTreeDocumentId(Uri, String)
+ */
public static boolean isTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
@@ -1204,6 +1223,41 @@
}
/**
+ * Removes the given document from a parent directory.
+ *
+ * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+ * This method is especially useful if the document can be in multiple parents.
+ *
+ * @param documentUri document with {@link Document#FLAG_SUPPORTS_REMOVE}
+ * @param parentDocumentUri parent document of the document to remove.
+ * @return true if the document was removed successfully.
+ */
+ public static boolean removeDocument(ContentResolver resolver, Uri documentUri,
+ Uri parentDocumentUri) {
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ documentUri.getAuthority());
+ try {
+ removeDocument(client, documentUri, parentDocumentUri);
+ return true;
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to remove document", e);
+ return false;
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+ }
+
+ /** {@hide} */
+ public static void removeDocument(ContentProviderClient client, Uri documentUri,
+ Uri parentDocumentUri) throws RemoteException {
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+ in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
+
+ client.call(METHOD_REMOVE_DOCUMENT, null, in);
+ }
+
+ /**
* Open the given image for thumbnail purposes, using any embedded EXIF
* thumbnail if available, and providing orientation hints from the parent
* image.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index bae928d..7a82cd1e 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -21,6 +21,7 @@
import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT;
import static android.provider.DocumentsContract.buildDocumentUri;
import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree;
@@ -300,6 +301,25 @@
throws FileNotFoundException {
throw new UnsupportedOperationException("Move not supported");
}
+
+ /**
+ * Removes the requested document or a document tree.
+ *
+ * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+ * This method is especially useful if the document can be in multiple parents.
+ *
+ * <p>It's the responsibility of the provider to revoke grants if the document is
+ * removed from the last parent, and effectively the document is deleted.
+ *
+ * @param documentId the document to remove.
+ * @param parentDocumentId the parent of the document to move.
+ */
+ @SuppressWarnings("unused")
+ public boolean removeDocument(String documentId, String parentDocumentId)
+ throws FileNotFoundException {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+
/**
* Return all roots currently provided. To display to users, you must define
* at least one root. You should avoid making network requests to keep this
@@ -822,6 +842,17 @@
// Original document no longer exists, clean up any grants.
revokeDocumentPermission(documentId);
+ } else if (METHOD_REMOVE_DOCUMENT.equals(method)) {
+ final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
+ final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
+
+ enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+ removeDocument(documentId, parentSourceId);
+
+ // It's responsibility of the provider to revoke any grants, as the document may be
+ // still attached to another parents.
+
} else {
throw new UnsupportedOperationException("Method not supported " + method);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc0d7d6..6e92ec1 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -501,6 +501,23 @@
"android.settings.USER_DICTIONARY_SETTINGS";
/**
+ * Activity Action: Show settings to configure the hardware keyboard layout.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ *
+ * @see android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_KEYBOARD_LAYOUT_SETTINGS =
+ "android.settings.KEYBOARD_LAYOUT_SETTINGS";
+
+ /**
* Activity Action: Adds a word to the user dictionary.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -4839,6 +4856,29 @@
"accessibility_display_magnification_auto_update";
/**
+ * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be
+ * modified from an AccessibilityService using the SoftKeyboardController.
+ *
+ * @hide
+ */
+ public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE =
+ "accessibility_soft_keyboard_mode";
+
+ /**
+ * Default soft keyboard behavior.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+
+ /**
+ * Soft keyboard is never shown.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
+ /**
* Setting that specifies whether timed text (captions) should be
* displayed in video content. Text display properties are controlled by
* the following settings:
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 24683cb..8ee9d1e 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -101,6 +101,12 @@
public static final String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
/**
+ * Broadcast intent to request all voicemail sources to perform a sync with the remote server.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
+
+ /**
* Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
* receiving package made this change.
*/
@@ -393,6 +399,14 @@
* <P>Type: INTEGER</P>
*/
public static final String CONFIGURATION_STATE = "configuration_state";
+ /**
+ * Value of {@link #CONFIGURATION_STATE} passed into
+ * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+ * {@link #CONFIGURATION_STATE} field is not to be changed
+ *
+ * @hide
+ */
+ public static final int CONFIGURATION_STATE_IGNORE = -1;
/** Value of {@link #CONFIGURATION_STATE} to indicate an all OK configuration status. */
public static final int CONFIGURATION_STATE_OK = 0;
/**
@@ -418,15 +432,50 @@
*/
public static final String DATA_CHANNEL_STATE = "data_channel_state";
/**
+ * Value of {@link #DATA_CHANNEL_STATE} passed into
+ * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+ * {@link #DATA_CHANNEL_STATE} field is not to be changed
+ *
+ * @hide
+ */
+ public static final int DATA_CHANNEL_STATE_IGNORE = -1;
+ /**
* Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel is working fine.
*/
public static final int DATA_CHANNEL_STATE_OK = 0;
/**
- * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel connection is not
- * working.
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel failed to find a
+ * suitable network to connect to the server.
*/
public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1;
/**
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel failed to find a
+ * suitable network to connect to the server, and the carrier requires using cellular
+ * data network to connect to the server.
+ */
+ public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2;
+ /**
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel received incorrect
+ * settings or credentials to connect to the server
+ */
+ public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3;
+ /**
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that a error has occurred in the data
+ * channel while communicating with the server
+ */
+ public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4;
+ /**
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that the server reported an internal
+ * error to the data channel.
+ */
+ public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5;
+ /**
+ * Value of {@link #DATA_CHANNEL_STATE} to indicate that while there is a suitable network,
+ * the data channel is unable to establish a connection with the server.
+ */
+ public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6;
+
+ /**
* The notification channel state of the voicemail source. This is the channel through which
* the source gets notified of new voicemails on the remote server.
* <P> Possible values:
@@ -438,6 +487,14 @@
*/
public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
/**
+ * Value of {@link #NOTIFICATION_CHANNEL_STATE} passed into
+ * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+ * {@link #NOTIFICATION_CHANNEL_STATE} field is not to be changed
+ *
+ * @hide
+ */
+ public static final int NOTIFICATION_CHANNEL_STATE_IGNORE = -1;
+ /**
* Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel is
* working fine.
*/
@@ -497,21 +554,22 @@
*/
public static void setStatus(Context context, PhoneAccountHandle accountHandle,
int configurationState, int dataChannelState, int notificationChannelState) {
- ContentResolver contentResolver = context.getContentResolver();
- Uri statusUri = buildSourceUri(context.getPackageName());
ContentValues values = new ContentValues();
values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
accountHandle.getComponentName().flattenToString());
values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
- values.put(Status.CONFIGURATION_STATE, configurationState);
- values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
- values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
-
- if (isStatusPresent(contentResolver, statusUri)) {
- contentResolver.update(statusUri, values, null, null);
- } else {
- contentResolver.insert(statusUri, values);
+ if(configurationState != CONFIGURATION_STATE_IGNORE) {
+ values.put(Status.CONFIGURATION_STATE, configurationState);
}
+ if(dataChannelState != DATA_CHANNEL_STATE_IGNORE) {
+ values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
+ }
+ if(notificationChannelState != NOTIFICATION_CHANNEL_STATE_IGNORE) {
+ values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
+ }
+ ContentResolver contentResolver = context.getContentResolver();
+ Uri statusUri = buildSourceUri(context.getPackageName());
+ contentResolver.insert(statusUri, values);
}
/**
@@ -540,28 +598,7 @@
ContentResolver contentResolver = context.getContentResolver();
Uri statusUri = buildSourceUri(context.getPackageName());
- if (isStatusPresent(contentResolver, statusUri)) {
- contentResolver.update(statusUri, values, null, null);
- } else {
- contentResolver.insert(statusUri, values);
- }
- }
-
- /**
- * Determines if a voicemail source exists in the status table.
- *
- * @param contentResolver A content resolver constructed from the appropriate context.
- * @param statusUri The content uri for the source.
- * @return {@code true} if a status entry for this source exists
- */
- private static boolean isStatusPresent(ContentResolver contentResolver, Uri statusUri) {
- Cursor cursor = null;
- try {
- cursor = contentResolver.query(statusUri, null, null, null, null);
- return cursor != null && cursor.getCount() != 0;
- } finally {
- if (cursor != null) cursor.close();
- }
+ contentResolver.insert(statusUri, values);
}
}
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index ac7d539..76a401d 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -31,6 +31,7 @@
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
import android.media.AudioFormat;
import android.os.AsyncTask;
import android.os.Handler;
@@ -616,7 +617,11 @@
}
@Override
- public void onDetected(KeyphraseRecognitionEvent event) {
+ public void onDetected(RecognitionEvent event) {
+ if (! (event instanceof KeyphraseRecognitionEvent)) {
+ Slog.e(TAG, "onDetected() called for a soundtrigger event.");
+ return;
+ }
if (DBG) {
Slog.d(TAG, "onDetected(" + event + ")");
} else {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 0c6a0c6..6ff9fe7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1170,7 +1170,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()));
Instrumentation.checkStartActivityResult(res, intent);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index cd19607..a985517 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -271,7 +271,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect) {
+ Configuration newConfig, Rect backDropRect, boolean forceLayout) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
mCaller.sendMessage(msg);
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index 2ecbfae..1e6bd9c 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -29,7 +29,13 @@
/**
* Extend this if you need to access Resources or other things that depend on Activity Context.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class AndroidTestCase extends TestCase {
protected Context mContext;
diff --git a/core/java/android/test/FlakyTest.java b/core/java/android/test/FlakyTest.java
index 919767f..4e5c4e3 100644
--- a/core/java/android/test/FlakyTest.java
+++ b/core/java/android/test/FlakyTest.java
@@ -26,7 +26,13 @@
* test methods. When the annotation is present, the test method is re-executed if
* the test fails. The total number of executions is specified by the tolerance and
* defaults to 1.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/FlakyTest.html">
+ * FlakyTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FlakyTest {
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index ca427ea..6b79314 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -32,7 +32,13 @@
/**
* A test case that has access to {@link Instrumentation}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class InstrumentationTestCase extends TestCase {
private Instrumentation mInstrumentation;
@@ -40,7 +46,7 @@
/**
* Injects instrumentation into this test case. This method is
* called by the test runner during test setup.
- *
+ *
* @param instrumentation the instrumentation to use with this instance
*/
public void injectInstrumentation(Instrumentation instrumentation) {
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java
index 7a78ffb..a53fa26 100644
--- a/core/java/android/test/InstrumentationTestSuite.java
+++ b/core/java/android/test/InstrumentationTestSuite.java
@@ -25,7 +25,13 @@
/**
* A {@link junit.framework.TestSuite} that injects {@link android.app.Instrumentation} into
* {@link InstrumentationTestCase} before running them.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class InstrumentationTestSuite extends TestSuite {
private final Instrumentation mInstrumentation;
diff --git a/core/java/android/test/PerformanceTestCase.java b/core/java/android/test/PerformanceTestCase.java
index 679ad40..65bd4a4 100644
--- a/core/java/android/test/PerformanceTestCase.java
+++ b/core/java/android/test/PerformanceTestCase.java
@@ -18,10 +18,11 @@
/**
* More complex interface performance for test cases.
- *
+ *
* If you want your test to be used as a performance test, you must
* implement this interface.
*/
+@Deprecated
public interface PerformanceTestCase
{
/**
@@ -37,27 +38,27 @@
}
/**
- * Set up to begin performance tests. The 'intermediates' is a
+ * Set up to begin performance tests. The 'intermediates' is a
* communication channel to send back intermediate performance numbers --
* if you use it, you will probably want to ensure your test is only
* executed once by returning 1. Otherwise, return 0 to allow the test
* harness to decide the number of iterations.
- *
+ *
* <p>If you return a non-zero iteration count, you should call
* {@link Intermediates#startTiming intermediates.startTiming} and
* {@link Intermediates#finishTiming intermediates.endTiming} to report the
* duration of the test whose performance should actually be measured.
- *
+ *
* @param intermediates Callback for sending intermediate results.
- *
+ *
* @return int Maximum number of iterations to run, or 0 to let the caller
- * decide.
+ * decide.
*/
int startPerformance(Intermediates intermediates);
-
+
/**
* This method is used to determine what modes this test case can run in.
- *
+ *
* @return true if this test case can only be run in performance mode.
*/
boolean isPerformanceOnly();
diff --git a/core/java/android/test/UiThreadTest.java b/core/java/android/test/UiThreadTest.java
index cd92231..cd06ab8 100644
--- a/core/java/android/test/UiThreadTest.java
+++ b/core/java/android/test/UiThreadTest.java
@@ -26,7 +26,13 @@
* When the annotation is present, the test method is executed on the application's
* main thread (or UI thread.) Note that instrumentation methods may not be used
* when this annotation is present.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/annotation/UiThreadTest.html">
+ * UiThreadTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UiThreadTest {
diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java
index a6269e7..dc77ee6 100644
--- a/core/java/android/test/suitebuilder/annotation/LargeTest.java
+++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java
@@ -23,7 +23,13 @@
/**
* Marks a test that should run as part of the large tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/LargeTest.html">
+ * LargeTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface LargeTest {
diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java
index 8afeb91..b941da0 100644
--- a/core/java/android/test/suitebuilder/annotation/MediumTest.java
+++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java
@@ -24,7 +24,12 @@
/**
* Marks a test that should run as part of the medium tests.
*
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/MediumTest.html">
+ * MediumTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MediumTest {
diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java
index ad530e2..d3c74f0 100644
--- a/core/java/android/test/suitebuilder/annotation/SmallTest.java
+++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java
@@ -23,7 +23,13 @@
/**
* Marks a test that should run as part of the small tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/SmallTest.html">
+ * SmallTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SmallTest {
diff --git a/core/java/android/test/suitebuilder/annotation/Smoke.java b/core/java/android/test/suitebuilder/annotation/Smoke.java
index 237e033..aac2937 100644
--- a/core/java/android/test/suitebuilder/annotation/Smoke.java
+++ b/core/java/android/test/suitebuilder/annotation/Smoke.java
@@ -27,7 +27,11 @@
* will run all tests with this annotation.
*
* @see android.test.suitebuilder.SmokeTestSuiteBuilder
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Smoke {
diff --git a/core/java/android/test/suitebuilder/annotation/Suppress.java b/core/java/android/test/suitebuilder/annotation/Suppress.java
index f16c8fa..629a3cf 100644
--- a/core/java/android/test/suitebuilder/annotation/Suppress.java
+++ b/core/java/android/test/suitebuilder/annotation/Suppress.java
@@ -26,7 +26,12 @@
* suite. If the annotation appears on the class then no tests in that class will be included. If
* the annotation appears only on a test method then only that method will be excluded.
*
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/Suppress.html">
+ * Suppress</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Suppress {
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 9a69600..a747f16 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -131,16 +131,29 @@
public static final float DENSITY_DEFAULT_SCALE = 1.0f / DENSITY_DEFAULT;
/**
- * The device's density.
- * @hide because eventually this should be able to change while
- * running, so shouldn't be a constant.
- * @deprecated There is no longer a static density; you can find the
- * density for a display in {@link #densityDpi}.
+ * The device's current density.
+ * <p>
+ * This value reflects any changes made to the device density. To obtain
+ * the device's stable density, use {@link #DENSITY_DEVICE_STABLE}.
+ *
+ * @hide This value should not be used.
+ * @deprecated Use {@link #DENSITY_DEVICE_STABLE} to obtain the stable
+ * device density or {@link #densityDpi} to obtain the current
+ * density for a specific display.
*/
@Deprecated
public static int DENSITY_DEVICE = getDeviceDensity();
/**
+ * The device's stable density.
+ * <p>
+ * This value is constant at run time and may not reflect the current
+ * display density. To obtain the current density for a specific display,
+ * use {@link #densityDpi}.
+ */
+ public static final int DENSITY_DEVICE_STABLE = getDeviceDensity();
+
+ /**
* The absolute width of the display in pixels.
*/
public int widthPixels;
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index c5ed39a..3688d50 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -49,7 +49,7 @@
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
- in Configuration newConfig, in Rect backDropFrame);
+ in Configuration newConfig, in Rect backDropFrame, boolean forceLayout);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b045c17..27ea92d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -101,15 +101,16 @@
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
* @param configuration Configuration that is being used with this task.
- * @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+ * @param taskResizeMode The resize mode of the task.
* @param alwaysFocusable True if the app windows are always focusable regardless of the stack
* they are in.
+ * @param homeTask True if this is the task.
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
- boolean alwaysFocusable);
+ in Rect taskBounds, in Configuration configuration, int taskResizeMode,
+ boolean alwaysFocusable, boolean homeTask);
/**
*
* @param token The token we are adding to the input task Id.
@@ -119,9 +120,11 @@
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
* @param config Configuration that is being used with this task.
+ * @param taskResizeMode The resize mode of the task.
+ * @param homeTask True if this is the task.
*/
- void setAppTask(
- IBinder token, int taskId, int stackId, in Rect taskBounds, in Configuration config);
+ void setAppTask(IBinder token, int taskId, int stackId, in Rect taskBounds,
+ in Configuration config, int taskResizeMode, boolean homeTask);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
index 013255b..57d07c0 100644
--- a/core/java/android/view/KeyboardShortcutGroup.java
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -32,6 +32,8 @@
public final class KeyboardShortcutGroup implements Parcelable {
private final CharSequence mLabel;
private final List<KeyboardShortcutInfo> mItems;
+ // The system group looks different UI wise.
+ private boolean mSystemGroup;
/**
* @param label The title to be used for this group, or null if there is none.
@@ -50,10 +52,33 @@
this(label, Collections.<KeyboardShortcutInfo>emptyList());
}
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ * @param items The set of items to be included.
+ * @param isSystemGroup Set this to {@code true} if this is s system group.
+ * @hide
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label,
+ @NonNull List<KeyboardShortcutInfo> items, boolean isSystemGroup) {
+ mLabel = label;
+ mItems = new ArrayList<>(checkNotNull(items));
+ mSystemGroup = isSystemGroup;
+ }
+
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ * @param isSystemGroup Set this to {@code true} if this is s system group.
+ * @hide
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label, boolean isSystemGroup) {
+ this(label, Collections.<KeyboardShortcutInfo>emptyList(), isSystemGroup);
+ }
+
private KeyboardShortcutGroup(Parcel source) {
mItems = new ArrayList<>();
mLabel = source.readCharSequence();
source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR);
+ mSystemGroup = source.readInt() == 1;
}
/**
@@ -70,6 +95,11 @@
return mItems;
}
+ /** @hide **/
+ public boolean isSystemGroup() {
+ return mSystemGroup;
+ }
+
/**
* Adds an item to the existing list.
*
@@ -88,6 +118,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mLabel);
dest.writeTypedList(mItems);
+ dest.writeInt(mSystemGroup ? 1 : 0);
}
public static final Creator<KeyboardShortcutGroup> CREATOR =
@@ -99,4 +130,4 @@
return new KeyboardShortcutGroup[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 1c0ea0f..34713ad 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -25,8 +25,6 @@
import android.widget.RemoteViews;
import android.widget.TextView;
-import com.android.internal.R;
-
import java.util.ArrayList;
/**
@@ -39,6 +37,7 @@
public static final int NO_COLOR = -1;
private final int mHeaderMinWidth;
private final int mExpandTopPadding;
+ private final int mContentEndMargin;
private View mAppName;
private View mSubTextView;
private OnClickListener mExpandClickListener;
@@ -51,6 +50,7 @@
private int mOriginalNotificationColor;
private boolean mGroupHeader;
private boolean mExpanded;
+ private boolean mShowWorkBadgeAtEnd;
public NotificationHeaderView(Context context) {
this(context, null);
@@ -68,6 +68,8 @@
super(context, attrs, defStyleAttr, defStyleRes);
mHeaderMinWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_header_shrink_min_width);
+ mContentEndMargin = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
}
@@ -135,6 +137,9 @@
super.onLayout(changed, l, t, r, b);
if (mProfileBadge.getVisibility() != View.GONE) {
int paddingEnd = getPaddingEnd();
+ if (mShowWorkBadgeAtEnd) {
+ paddingEnd = mContentEndMargin;
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
mProfileBadge.layout(paddingEnd,
mProfileBadge.getTop(),
@@ -225,6 +230,17 @@
mExpandButton.setPadding(0, paddingTop, 0, 0);
}
+ public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
+ if (showWorkBadgeAtEnd != mShowWorkBadgeAtEnd) {
+ setClipToPadding(!showWorkBadgeAtEnd);
+ mShowWorkBadgeAtEnd = showWorkBadgeAtEnd;
+ }
+ }
+
+ public View getWorkProfileIcon() {
+ return mProfileBadge;
+ }
+
public class HeaderTouchListener implements View.OnTouchListener {
private final ArrayList<Rect> mTouchRects = new ArrayList<>();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7ba046b..81bb638 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -139,9 +139,7 @@
private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
-
- /** @hide */
- public static boolean sUseLargeIcons = false;
+ private static boolean sUseLargeIcons = false;
private final int mStyle;
private int mSystemIconResourceId;
@@ -235,6 +233,15 @@
}
/**
+ * Updates wheter accessibility large icons are used or not.
+ * @hide
+ */
+ public static void setUseLargeIcons(boolean use) {
+ sUseLargeIcons = use;
+ gSystemIcons.clear();
+ }
+
+ /**
* Creates a custom pointer from the given bitmap and hotspot information.
*
* @param bitmap The bitmap for the icon.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9f6d3e5..5b48e28 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -698,7 +698,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect) {
+ Configuration newConfig, Rect backDropRect, boolean forceLayout) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
if (DEBUG) Log.v(
@@ -711,7 +711,8 @@
surfaceView.mReportDrawNeeded = true;
surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
} else if (surfaceView.mWinFrame.width() != frame.width()
- || surfaceView.mWinFrame.height() != frame.height()) {
+ || surfaceView.mWinFrame.height() != frame.height()
+ || forceLayout) {
surfaceView.mUpdateWindowNeeded = true;
surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5d41477..98e3289 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -263,6 +264,7 @@
boolean mNewSurfaceNeeded;
boolean mHasHadWindowFocus;
boolean mLastWasImTarget;
+ boolean mForceNextWindowRelayout;
CountDownLatch mWindowDrawCountDown;
boolean mIsDrawing;
@@ -1625,7 +1627,8 @@
final boolean isViewVisible = viewVisibility == View.VISIBLE;
if (mFirst || windowShouldResize || insetsChanged ||
- viewVisibilityChanged || params != null) {
+ viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
+ mForceNextWindowRelayout = false;
if (isViewVisible) {
// If this window is giving internal insets to the window
@@ -2099,7 +2102,7 @@
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
- if (!cancelDraw && !newSurface) {
+ if (!cancelDraw) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
@@ -2148,6 +2151,7 @@
}
}
}
+
private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
try {
@@ -3365,7 +3369,8 @@
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
- && args.arg4 == null) {
+ && args.arg4 == null
+ && args.argi1 == 0) {
break;
}
} // fall through...
@@ -3385,6 +3390,7 @@
mPendingVisibleInsets.set((Rect) args.arg3);
mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
+ mForceNextWindowRelayout = args.argi1 != 0;
args.recycle();
@@ -5829,7 +5835,7 @@
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame) {
+ Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -5863,6 +5869,7 @@
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
+ args.argi1 = forceLayout ? 1 : 0;
msg.obj = args;
mHandler.sendMessage(msg);
}
@@ -6878,11 +6885,12 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame) {
+ Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame);
+ visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
+ forceLayout);
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 772eeec..0c5a5fc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -589,14 +589,14 @@
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
/**
- * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * Window type: Windows that are overlaid <em>only</em> by a connected {@link
* android.accessibilityservice.AccessibilityService} for interception of
* user interactions without changing the windows an accessibility service
* can introspect. In particular, an accessibility service can introspect
* only windows that a sighted user can interact with which is they can touch
* these windows or can type into these windows. For example, if there
* is a full screen accessibility overlay that is touchable, the windows
- * below it will be introspectable by an accessibility service regardless
+ * below it will be introspectable by an accessibility service even though
* they are covered by a touchable window.
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1327ea1..b673386 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -38,8 +38,8 @@
/**
* This class represents a node of the window content as well as actions that
* can be requested from its source. From the point of view of an
- * {@link android.accessibilityservice.AccessibilityService} a window content is
- * presented as tree of accessibility node info which may or may not map one-to-one
+ * {@link android.accessibilityservice.AccessibilityService} a window's content is
+ * presented as a tree of accessibility node infos, which may or may not map one-to-one
* to the view hierarchy. In other words, a custom view is free to report itself as
* a tree of accessibility node info.
* </p>
@@ -50,7 +50,7 @@
* <p>
* Please refer to {@link android.accessibilityservice.AccessibilityService} for
* details about how to obtain a handle to window content as a tree of accessibility
- * node info as well as familiarizing with the security model.
+ * node info as well as details about the security model.
* </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
@@ -2422,18 +2422,30 @@
}
/**
- * Gets the text selection start.
+ * Gets the text selection start or the cursor position.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection start if there is selection or -1.
+ * @return The text selection start, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionStart() {
return mTextSelectionStart;
}
/**
- * Gets the text selection end.
+ * Gets the text selection end if text is selected.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection end if there is selection or -1.
+ * @return The text selection end, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionEnd() {
return mTextSelectionEnd;
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9e79057..655c9b3 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -51,7 +51,7 @@
void removeAccessibilityInteractionConnection(IWindow windowToken);
void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient client,
- in AccessibilityServiceInfo info);
+ in AccessibilityServiceInfo info, int flags);
void unregisterUiTestAutomationService(IAccessibilityServiceClient client);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index df84970..7b6fa6d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -565,6 +565,12 @@
private Runnable mTouchModeReset;
/**
+ * Whether the most recent touch event stream resulted in a successful
+ * long-press action. This is reset on TOUCH_DOWN.
+ */
+ private boolean mHasPerformedLongPress;
+
+ /**
* This view is in transcript mode -- it shows the bottom of the list when the data
* changes
*/
@@ -3108,7 +3114,9 @@
handled = performLongPress(child, longPressPosition, longPressId);
}
}
+
if (handled) {
+ mHasPerformedLongPress = true;
mTouchMode = TOUCH_MODE_REST;
setPressed(false);
child.setPressed(false);
@@ -3811,6 +3819,7 @@
}
private void onTouchDown(MotionEvent ev) {
+ mHasPerformedLongPress = false;
mActivePointerId = ev.getPointerId(0);
if (mTouchMode == TOUCH_MODE_OVERFLING) {
@@ -3874,6 +3883,11 @@
}
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
+ if (mHasPerformedLongPress) {
+ // Consume all move events following a successful long press.
+ return;
+ }
+
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
pointerIndex = 0;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 617d3dd..3a61fcd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2872,6 +2872,7 @@
protected PopupWindow mPopupWindow;
protected ViewGroup mContentView;
int mPositionX, mPositionY;
+ int mClippingLimitLeft, mClippingLimitRight;
protected abstract void createPopupWindow();
protected abstract void initContentView();
@@ -2939,8 +2940,9 @@
// Horizontal clipping
final DisplayMetrics displayMetrics = mTextView.getResources().getDisplayMetrics();
final int width = mContentView.getMeasuredWidth();
- positionX = Math.min(displayMetrics.widthPixels - width, positionX);
- positionX = Math.max(0, positionX);
+ positionX = Math.min(
+ displayMetrics.widthPixels - width + mClippingLimitRight, positionX);
+ positionX = Math.max(-mClippingLimitLeft, positionX);
if (isShowing()) {
mPopupWindow.update(positionX, positionY, -1, -1);
@@ -3118,6 +3120,8 @@
private TextView mAddToDictionaryButton;
private TextView mDeleteButton;
private SuggestionSpan mMisspelledSpan;
+ private int mContainerMarginWidth;
+ private int mContainerMarginTop;
private class CustomPopupWindow extends PopupWindow {
@Override
@@ -3155,10 +3159,20 @@
protected void initContentView() {
final LayoutInflater inflater = (LayoutInflater) mTextView.getContext().
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- final LinearLayout linearLayout = (LinearLayout) inflater.inflate(
+ final ViewGroup relativeLayout = (ViewGroup) inflater.inflate(
mTextView.mTextEditSuggestionContainerLayout, null);
- final ListView suggestionListView = (ListView) linearLayout.findViewById(
+ final LinearLayout suggestionWindowContainer =
+ (LinearLayout) relativeLayout.findViewById(
+ com.android.internal.R.id.suggestionWindowContainer);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) suggestionWindowContainer.getLayoutParams();
+ mContainerMarginWidth = lp.leftMargin + lp.rightMargin;
+ mContainerMarginTop = lp.topMargin;
+ mClippingLimitLeft = lp.leftMargin;
+ mClippingLimitRight = lp.rightMargin;
+
+ final ListView suggestionListView = (ListView) relativeLayout.findViewById(
com.android.internal.R.id.suggestionContainer);
mSuggestionsAdapter = new SuggestionAdapter();
@@ -3171,9 +3185,9 @@
mSuggestionInfos[i] = new SuggestionInfo();
}
- mContentView = linearLayout;
+ mContentView = relativeLayout;
- mAddToDictionaryButton = (TextView) linearLayout.findViewById(
+ mAddToDictionaryButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.addToDictionaryButton);
mAddToDictionaryButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3197,7 +3211,7 @@
}
});
- mDeleteButton = (TextView) linearLayout.findViewById(
+ mDeleteButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.deleteButton);
mDeleteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3306,6 +3320,8 @@
mDeleteButton.measure(horizontalMeasure, verticalMeasure);
width = Math.max(width, mDeleteButton.getMeasuredWidth());
+ width += mContainerMarginWidth;
+
// Enforce the width based on actual text widths
mContentView.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
@@ -3327,7 +3343,7 @@
@Override
protected int getVerticalLocalPosition(int line) {
- return mTextView.getLayout().getLineBottom(line);
+ return mTextView.getLayout().getLineBottom(line) - mContainerMarginTop;
}
@Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b7b7400..2733391 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -66,6 +66,7 @@
import android.widget.ListView;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import java.util.ArrayList;
import java.util.Collections;
@@ -209,7 +210,7 @@
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
- MetricsLogger.action(this, MetricsLogger.ACTION_ACTIVITY_CHOOSER_SHOWN);
+ MetricsLogger.action(this, MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
}
@Override
@@ -349,14 +350,14 @@
int value = which;
switch (mChooserListAdapter.getPositionTargetType(which)) {
case ChooserListAdapter.TARGET_CALLER:
- cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
+ cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
break;
case ChooserListAdapter.TARGET_SERVICE:
- cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
+ cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
value -= mChooserListAdapter.getCallerTargetCount();
break;
case ChooserListAdapter.TARGET_STANDARD:
- cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
+ cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
value -= mChooserListAdapter.getCallerTargetCount()
+ mChooserListAdapter.getServiceTargetCount();
break;
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
index 53d7793..03da9bc 100644
--- a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -64,6 +64,10 @@
String message = checkUserCreationRequirements();
+ if (message == null) {
+ finish();
+ return;
+ }
final AlertController.AlertParams ap = mAlertParams;
ap.mMessage = message;
ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -104,11 +108,11 @@
mCanProceed = true;
final String appName = appInfo.loadLabel(getPackageManager()).toString();
if (cantCreateUser) {
- message = getString(R.string.user_creation_cannot_add, appName);
- mCanProceed = false;
+ setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
+ return null;
} else if (cantCreateAnyMoreUsers) {
- message = getString(R.string.user_creation_cannot_add_any_more, appName);
- mCanProceed = false;
+ setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS);
+ return null;
} else if (accountExists) {
message = getString(R.string.user_creation_account_exists, appName, mAccountName);
} else {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 3b9b8db..ec53a2e 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -121,4 +121,7 @@
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
+
+ void noteBleScanStarted(in WorkSource ws);
+ void noteBleScanStopped(in WorkSource ws);
}
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
new file mode 100644
index 0000000..9de4a6c
--- /dev/null
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.ParcelUuid;
+
+/**
+ * Service interface for a generic sound recognition model.
+ * @hide
+ */
+interface ISoundTriggerService {
+
+
+ SoundTrigger.GenericSoundModel getSoundModel(in ParcelUuid soundModelId);
+
+ void updateSoundModel(in SoundTrigger.GenericSoundModel soundModel);
+
+ void deleteSoundModel(in ParcelUuid soundModelId);
+
+ void startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+
+ /**
+ * Stops recognition.
+ */
+ void stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 71c2c21..c7459d7 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.icu.util.ULocale;
+import android.icu.text.ListFormatter;
import android.util.LocaleList;
import java.text.Collator;
@@ -145,20 +146,16 @@
* @return the locale aware list of locale names
*/
public static String getDisplayLocaleList(LocaleList locales, Locale displayLocale) {
- final StringBuilder result = new StringBuilder();
-
final Locale dispLocale = displayLocale == null ? Locale.getDefault() : displayLocale;
+
int localeCount = locales.size();
+ final String[] localeNames = new String[localeCount];
for (int i = 0; i < localeCount; i++) {
- Locale locale = locales.get(i);
- result.append(LocaleHelper.getDisplayName(locale, dispLocale, false));
- // TODO: language aware list formatter. ICU has one.
- if (i < localeCount - 1) {
- result.append(", ");
- }
+ localeNames[i] = LocaleHelper.getDisplayName(locales.get(i), dispLocale, false);
}
- return result.toString();
+ ListFormatter lfn = ListFormatter.getInstance(dispLocale);
+ return lfn.format(localeNames);
}
/**
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index b951f50e..d3bae16 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -133,7 +133,7 @@
notificationId = -1;
}
- // Respond to NI Handler under GpsLocationProvider, 1 = accept, 2 = deny
+ // Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
private void sendUserResponse(int response) {
if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
LocationManager locationManager = (LocationManager)
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index aa38de7..ec148c55 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1231,7 +1231,9 @@
}
// Filter out any activities that the launched uid does not
- // have permission for. We don't do this when we have an explicit
+ // have permission for.
+ // Also filter out those that are suspended because they couldn't
+ // be started. We don't do this when we have an explicit
// list of resolved activities, because that only happens when
// we are being subclassed, so we can safely launch whatever
// they gave us.
@@ -1242,7 +1244,9 @@
int granted = ActivityManager.checkComponentPermission(
ai.permission, mLaunchedFromUid,
ai.applicationInfo.uid, ai.exported);
- if (granted != PackageManager.PERMISSION_GRANTED) {
+ boolean suspended = (ai.applicationInfo.flags
+ & ApplicationInfo.FLAG_SUSPENDED) != 0;
+ if (granted != PackageManager.PERMISSION_GRANTED || suspended) {
// Access not allowed!
if (mOrigResolveList == currentResolveList) {
mOrigResolveList = new ArrayList<>(mOrigResolveList);
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index aada6e3..29190f9 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -32,6 +32,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -69,12 +70,11 @@
}
String dialogTitle;
- String dialogMessage;
+ String dialogMessage = null;
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
dialogTitle = getResources().getString(R.string.work_mode_off_title);
dialogMessage = getResources().getString(R.string.work_mode_off_message);
} else if (mReason == UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE) {
- PackageManager pm = getPackageManager();
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
@@ -91,12 +91,19 @@
}
dialogTitle = String.format(getResources().getString(R.string.suspended_package_title),
packageLabel);
- dialogMessage = dpm.getShortSupportMessageForUser(dpm.getProfileOwnerAsUser(mUserId),
- mUserId);
- if (dialogMessage == null) {
- dialogMessage = String.format(
- getResources().getString(R.string.suspended_package_message),
- dpm.getProfileOwnerNameAsUser(mUserId));
+ ComponentName profileOwner = dpm.getProfileOwnerAsUser(mUserId);
+ String profileOwnerName = null;
+ if (profileOwner != null) {
+ dialogMessage = dpm.getShortSupportMessageForUser(profileOwner, mUserId);
+ profileOwnerName = dpm.getProfileOwnerNameAsUser(mUserId);
+ }
+ // Fall back to standard message if profile owner hasn't set something specific.
+ if (TextUtils.isEmpty(dialogMessage)) {
+ if (TextUtils.isEmpty(profileOwnerName)) {
+ profileOwnerName = getResources().getString(R.string.unknownName);
+ }
+ dialogMessage = getResources().getString(R.string.suspended_package_message,
+ profileOwnerName);
}
} else {
Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 8cdfc64..10027b6 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -101,9 +101,6 @@
private void makeDataDirs() {
mCurrentSetDir.mkdirs();
- if (!SELinux.restorecon(mCurrentSetDir)) {
- Log.e(TAG, "SELinux restorecon failed for " + mCurrentSetDir);
- }
mCurrentSetFullDir.mkdir();
mCurrentSetIncrementalDir.mkdir();
}
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
deleted file mode 100644
index 522732d..0000000
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * 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.logging;
-
-/**
- * Constants for mestrics logs.
- *
- * @hide
- */
-public interface MetricsConstants {
- // These constants must match those in the analytic pipeline, do not edit.
- // define metric categories in frameworks/base/core/proto/src/metrics_constants.proto.
- public static final int MAIN_SETTINGS = 1;
- public static final int ACCESSIBILITY = 2;
- public static final int ACCESSIBILITY_CAPTION_PROPERTIES = 3;
- public static final int ACCESSIBILITY_SERVICE = 4;
- public static final int ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
- public static final int ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
- public static final int ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
- public static final int ACCOUNT = 8;
- public static final int ACCOUNTS_ACCOUNT_SYNC = 9;
- public static final int ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
- public static final int ACCOUNTS_MANAGE_ACCOUNTS = 11;
- public static final int APN = 12;
- public static final int APN_EDITOR = 13;
- public static final int APP_OPS_DETAILS = 14;
- public static final int APP_OPS_SUMMARY = 15;
- public static final int APPLICATION = 16;
- public static final int APPLICATIONS_APP_LAUNCH = 17;
- public static final int APPLICATIONS_APP_PERMISSION = 18;
- public static final int APPLICATIONS_APP_STORAGE = 19;
- public static final int APPLICATIONS_INSTALLED_APP_DETAILS = 20;
- public static final int APPLICATIONS_PROCESS_STATS_DETAIL = 21;
- public static final int APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
- public static final int APPLICATIONS_PROCESS_STATS_UI = 23;
- public static final int BLUETOOTH = 24;
- public static final int BLUETOOTH_DEVICE_PICKER = 25;
- public static final int BLUETOOTH_DEVICE_PROFILES = 26;
- public static final int CHOOSE_LOCK_GENERIC = 27;
- public static final int CHOOSE_LOCK_PASSWORD = 28;
- public static final int CHOOSE_LOCK_PATTERN = 29;
- public static final int CONFIRM_LOCK_PASSWORD = 30;
- public static final int CONFIRM_LOCK_PATTERN = 31;
- public static final int CRYPT_KEEPER = 32;
- public static final int CRYPT_KEEPER_CONFIRM = 33;
- public static final int DASHBOARD_SEARCH_RESULTS = 34;
- public static final int DASHBOARD_SUMMARY = 35;
- public static final int DATA_USAGE = 36;
- public static final int DATA_USAGE_SUMMARY = 37;
- public static final int DATE_TIME = 38;
- public static final int DEVELOPMENT = 39;
- public static final int DEVICEINFO = 40;
- public static final int DEVICEINFO_IMEI_INFORMATION = 41;
- public static final int DEVICEINFO_STORAGE = 42;
- public static final int DEVICEINFO_SIM_STATUS = 43;
- public static final int DEVICEINFO_STATUS = 44;
- public static final int DEVICEINFO_USB = 45;
- public static final int DISPLAY = 46;
- public static final int DREAM = 47;
- public static final int ENCRYPTION = 48;
- public static final int FINGERPRINT = 49;
- public static final int FINGERPRINT_ENROLL = 50;
- public static final int FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
- public static final int FUELGAUGE_BATTERY_SAVER = 52;
- public static final int FUELGAUGE_POWER_USAGE_DETAIL = 53;
- public static final int FUELGAUGE_POWER_USAGE_SUMMARY = 54;
- public static final int HOME = 55;
- public static final int ICC_LOCK = 56;
- public static final int INPUTMETHOD_LANGUAGE = 57;
- public static final int INPUTMETHOD_KEYBOARD = 58;
- public static final int INPUTMETHOD_SPELL_CHECKERS = 59;
- public static final int INPUTMETHOD_SUBTYPE_ENABLER = 60;
- public static final int INPUTMETHOD_USER_DICTIONARY = 61;
- public static final int INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
- public static final int LOCATION = 63;
- public static final int LOCATION_MODE = 64;
- public static final int MANAGE_APPLICATIONS = 65;
- public static final int MASTER_CLEAR = 66;
- public static final int MASTER_CLEAR_CONFIRM = 67;
- public static final int NET_DATA_USAGE_METERED = 68;
- public static final int NFC_BEAM = 69;
- public static final int NFC_PAYMENT = 70;
- public static final int NOTIFICATION = 71;
- public static final int NOTIFICATION_APP_NOTIFICATION = 72;
- public static final int NOTIFICATION_OTHER_SOUND = 73;
- public static final int NOTIFICATION_REDACTION = 74;
- public static final int NOTIFICATION_STATION = 75;
- public static final int NOTIFICATION_ZEN_MODE = 76;
- public static final int OWNER_INFO = 77;
- public static final int PRINT_JOB_SETTINGS = 78;
- public static final int PRINT_SERVICE_SETTINGS = 79;
- public static final int PRINT_SETTINGS = 80;
- public static final int PRIVACY = 81;
- public static final int PROXY_SELECTOR = 82;
- public static final int RESET_NETWORK = 83;
- public static final int RESET_NETWORK_CONFIRM = 84;
- public static final int RUNNING_SERVICE_DETAILS = 85;
- public static final int SCREEN_PINNING = 86;
- public static final int SECURITY = 87;
- public static final int SIM = 88;
- public static final int TESTING = 89;
- public static final int TETHER = 90;
- public static final int TRUST_AGENT = 91;
- public static final int TRUSTED_CREDENTIALS = 92;
- public static final int TTS_ENGINE_SETTINGS = 93;
- public static final int TTS_TEXT_TO_SPEECH = 94;
- public static final int USAGE_ACCESS = 95;
- public static final int USER = 96;
- public static final int USERS_APP_RESTRICTIONS = 97;
- public static final int USER_DETAILS = 98;
- public static final int VOICE_INPUT = 99;
- public static final int VPN = 100;
- public static final int WALLPAPER_TYPE = 101;
- public static final int WFD_WIFI_DISPLAY = 102;
- public static final int WIFI = 103;
- public static final int WIFI_ADVANCED = 104;
- public static final int WIFI_CALLING = 105;
- public static final int WIFI_SAVED_ACCESS_POINTS = 106;
- public static final int WIFI_APITEST = 107;
- public static final int WIFI_INFO = 108;
- public static final int WIFI_P2P = 109;
- public static final int WIRELESS = 110;
- public static final int QS_AIRPLANEMODE = 112;
- public static final int QS_BLUETOOTH = 113;
- public static final int QS_CAST = 114;
- public static final int QS_CELLULAR = 115;
- public static final int QS_COLORINVERSION = 116;
- public static final int QS_DATAUSAGEDETAIL = 117;
- public static final int QS_DND = 118;
- public static final int QS_FLASHLIGHT = 119;
- public static final int QS_HOTSPOT = 120;
- public static final int QS_INTENT = 121;
- public static final int QS_LOCATION = 122;
- public static final int QS_ROTATIONLOCK = 123;
- public static final int QS_USERDETAILITE = 124;
- public static final int QS_USERDETAIL = 125;
- public static final int QS_WIFI = 126;
- public static final int NOTIFICATION_PANEL = 127;
- public static final int NOTIFICATION_ITEM = 128;
- public static final int NOTIFICATION_ITEM_ACTION = 129;
- public static final int APPLICATIONS_ADVANCED = 130;
- public static final int LOCATION_SCANNING = 131;
- public static final int MANAGE_APPLICATIONS_ALL = 132;
- public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
- public static final int ACTION_WIFI_ADD_NETWORK = 134;
- public static final int ACTION_WIFI_CONNECT = 135;
- public static final int ACTION_WIFI_FORCE_SCAN = 136;
- public static final int ACTION_WIFI_FORGET = 137;
- public static final int ACTION_WIFI_OFF = 138;
- public static final int ACTION_WIFI_ON = 139;
- public static final int MANAGE_PERMISSIONS = 140;
- public static final int NOTIFICATION_ZEN_MODE_PRIORITY = 141;
- public static final int NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
- public static final int MANAGE_DOMAIN_URLS = 143;
- public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
- public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
- public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
- public static final int ACTION_BAN_APP_NOTES = 147;
- public static final int ACTION_DISMISS_ALL_NOTES = 148;
- public static final int QS_DND_DETAILS = 149;
- public static final int QS_BLUETOOTH_DETAILS = 150;
- public static final int QS_CAST_DETAILS = 151;
- public static final int QS_WIFI_DETAILS = 152;
- public static final int QS_WIFI_TOGGLE = 153;
- public static final int QS_BLUETOOTH_TOGGLE = 154;
- public static final int QS_CELLULAR_TOGGLE = 155;
- public static final int QS_SWITCH_USER = 156;
- public static final int QS_CAST_SELECT = 157;
- public static final int QS_CAST_DISCONNECT = 158;
- public static final int ACTION_BLUETOOTH_TOGGLE = 159;
- public static final int ACTION_BLUETOOTH_SCAN = 160;
- public static final int ACTION_BLUETOOTH_RENAME = 161;
- public static final int ACTION_BLUETOOTH_FILES = 162;
- public static final int QS_DND_TIME = 163;
- public static final int QS_DND_CONDITION_SELECT = 164;
- public static final int QS_DND_ZEN_SELECT = 165;
- public static final int QS_DND_TOGGLE = 166;
- public static final int ACTION_ZEN_ALLOW_REMINDERS = 167;
- public static final int ACTION_ZEN_ALLOW_EVENTS = 168;
- public static final int ACTION_ZEN_ALLOW_MESSAGES = 169;
- public static final int ACTION_ZEN_ALLOW_CALLS = 170;
- public static final int ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
- public static final int ACTION_ZEN_ADD_RULE = 172;
- public static final int ACTION_ZEN_ADD_RULE_OK = 173;
- public static final int ACTION_ZEN_DELETE_RULE = 174;
- public static final int ACTION_ZEN_DELETE_RULE_OK = 175;
- public static final int ACTION_ZEN_ENABLE_RULE = 176;
- public static final int ACTION_AIRPLANE_TOGGLE = 177;
- public static final int ACTION_CELL_DATA_TOGGLE = 178;
- public static final int NOTIFICATION_ACCESS = 179;
- public static final int NOTIFICATION_ZEN_MODE_ACCESS = 180;
- public static final int APPLICATIONS_DEFAULT_APPS = 181;
- public static final int APPLICATIONS_STORAGE_APPS = 182;
- public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
- public static final int APPLICATIONS_HIGH_POWER_APPS = 184;
- public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185;
- public static final int ACTION_LS_UNLOCK = 186;
- public static final int ACTION_LS_SHADE = 187;
- public static final int ACTION_LS_HINT = 188;
- public static final int ACTION_LS_CAMERA = 189;
- public static final int ACTION_LS_DIALER = 190;
- public static final int ACTION_LS_LOCK = 191;
- public static final int ACTION_LS_NOTE = 192;
- public static final int ACTION_LS_QS = 193;
- public static final int ACTION_SHADE_QS_PULL = 194;
- public static final int ACTION_SHADE_QS_TAP = 195;
- public static final int LOCKSCREEN = 196;
- public static final int BOUNCER = 197;
- public static final int SCREEN = 198;
- public static final int NOTIFICATION_ALERT = 199;
- public static final int ACTION_EMERGENCY_CALL = 200;
- public static final int APPLICATIONS_MANAGE_ASSIST = 201;
- public static final int PROCESS_STATS_SUMMARY = 202;
- public static final int ACTION_ROTATION_LOCK = 203;
- public static final int ACTION_NOTE_CONTROLS = 204;
- public static final int ACTION_NOTE_INFO = 205;
- public static final int ACTION_APP_NOTE_SETTINGS = 206;
- public static final int VOLUME_DIALOG = 207;
- public static final int VOLUME_DIALOG_DETAILS = 208;
- public static final int ACTION_VOLUME_SLIDER = 209;
- public static final int ACTION_VOLUME_STREAM = 210;
- public static final int ACTION_VOLUME_KEY = 211;
- public static final int ACTION_VOLUME_ICON = 212;
- public static final int ACTION_RINGER_MODE = 213;
- public static final int ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
- public static final int ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
- public static final int ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
- public static final int ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
- public static final int ACTION_BRIGHTNESS = 218;
- public static final int ACTION_BRIGHTNESS_AUTO = 219;
- public static final int BRIGHTNESS_DIALOG = 220;
- public static final int SYSTEM_ALERT_WINDOW_APPS = 221;
- public static final int DREAMING = 222;
- public static final int DOZING = 223;
- public static final int OVERVIEW_ACTIVITY = 224;
- public static final int ABOUT_LEGAL_SETTINGS = 225;
- public static final int ACTION_SEARCH_RESULTS = 226;
- public static final int TUNER = 227;
- public static final int TUNER_QS = 228;
- public static final int TUNER_DEMO_MODE = 229;
- public static final int TUNER_QS_REORDER = 230;
- public static final int TUNER_QS_ADD = 231;
- public static final int TUNER_QS_REMOVE = 232;
- public static final int TUNER_STATUS_BAR_ENABLE = 233;
- public static final int TUNER_STATUS_BAR_DISABLE = 234;
- public static final int TUNER_DEMO_MODE_ENABLED = 235;
- public static final int TUNER_DEMO_MODE_ON = 236;
- public static final int TUNER_BATTERY_PERCENTAGE = 237;
- public static final int FUELGAUGE_INACTIVE_APPS = 238;
- public static final int ACTION_ASSIST_LONG_PRESS = 239;
- public static final int FINGERPRINT_ENROLLING = 240;
- public static final int FINGERPRINT_FIND_SENSOR = 241;
- public static final int FINGERPRINT_ENROLL_FINISH = 242;
- public static final int FINGERPRINT_ENROLL_INTRO = 243;
- public static final int FINGERPRINT_ENROLL_ONBOARD = 244;
- public static final int FINGERPRINT_ENROLL_SIDECAR = 245;
- public static final int FINGERPRINT_ENROLLING_SETUP = 246;
- public static final int FINGERPRINT_FIND_SENSOR_SETUP = 247;
- public static final int FINGERPRINT_ENROLL_FINISH_SETUP = 248;
- public static final int FINGERPRINT_ENROLL_INTRO_SETUP = 249;
- public static final int FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
- public static final int ACTION_FINGERPRINT_ENROLL = 251;
- public static final int ACTION_FINGERPRINT_AUTH = 252;
- public static final int ACTION_FINGERPRINT_DELETE = 253;
- public static final int ACTION_FINGERPRINT_RENAME = 254;
- public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
- public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
- public static final int QS_WORKMODE = 257;
- public static final int BACKGROUND_CHECK_SUMMARY = 258;
- public static final int QS_LOCK_TILE = 259;
- public static final int QS_USER_TILE = 260;
- public static final int QS_BATTERY_TILE = 261;
- public static final int NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
- public static final int ACTION_ZEN_ALLOW_PEEK = 263;
- public static final int ACTION_ZEN_ALLOW_LIGHTS = 264;
- public static final int NOTIFICATION_TOPIC_NOTIFICATION = 265;
- public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 266;
- public static final int QS_COLOR_MATRIX = 267;
- public static final int QS_CUSTOM = 268;
- public static final int ACTION_ZEN_ALLOW_SCREEN_ON = 269;
-
- /**
- * Logged when the user docks a window from recents by longpressing a task and dragging it to
- * the dock area.
- */
- public static final int ACTION_WINDOW_DOCK_DRAG_DROP = 270;
-
- /**
- * Logged when the user docks a fullscreen window by long pressing recents which also opens
- * recents on the lower/right side.
- */
- public static final int ACTION_WINDOW_DOCK_LONGPRESS = 271;
-
- /**
- * Logged when the user docks a window by dragging from the navbar which also opens recents on
- * the lower/right side.
- */
- public static final int ACTION_WINDOW_DOCK_SWIPE = 272;
-
- /**
- * Logged when the user launches a profile-specific app and we intercept it with the confirm
- * credentials UI.
- */
- public static final int PROFILE_CHALLENGE = 273;
- public static final int QS_BATTERY_DETAIL = 274;
-
- /**
- * Logged when the user goes into the overview history.
- */
- public static final int OVERVIEW_HISTORY = 275;
-
- /**
- * Logged when the user pages through overview.
- */
- public static final int ACTION_OVERVIEW_PAGE = 276;
-
- /**
- * Logged when the user launches a task from overview.
- */
- public static final int ACTION_OVERVIEW_SELECT = 277;
-
- /** Logged when the user views the emergency info. */
- public static final int ACTION_VIEW_EMERGENCY_INFO = 278;
-
- /** Logged when the user views the edit emergency info activity. */
- public static final int ACTION_EDIT_EMERGENCY_INFO = 279;
-
- /** Logged when the user edits an emergency info field. */
- public static final int ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
-
- /** Logged when the user adds a new emergency contact. */
- public static final int ACTION_ADD_EMERGENCY_CONTACT = 281;
-
- /** Logged when the user deletes an emergency contact. */
- public static final int ACTION_DELETE_EMERGENCY_CONTACT = 282;
-
- /** Logged when the user calls an emergency contact. */
- public static final int ACTION_CALL_EMERGENCY_CONTACT = 283;
-}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 183d8d7..ef725da 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,8 +26,8 @@
*
* @hide
*/
-public class MetricsLogger implements com.android.internal.logging.MetricsConstants {
- // define metric categories in frameworks/base/core/proto/src/metrics_constants.proto.
+public class MetricsLogger {
+ // define metric categories in frameworks/base/proto/src/metrics_constants.proto.
public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 57220b1..e2ccaae 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -41,6 +41,7 @@
import android.os.SystemProperties;
import android.os.WorkSource;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -106,7 +107,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 139 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 140 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -119,6 +120,12 @@
// in to one common name.
private static final int MAX_WAKELOCKS_PER_UID = 100;
+ // Number of transmit power states the Wifi controller can be in.
+ private static final int NUM_WIFI_TX_LEVELS = 1;
+
+ // Number of transmit power states the Bluetooth controller can be in.
+ private static final int NUM_BT_TX_LEVELS = 1;
+
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
@@ -379,11 +386,38 @@
final LongSamplingCounter[] mNetworkPacketActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
- final LongSamplingCounter[] mBluetoothActivityCounters =
- new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+ /**
+ * The WiFi controller activity (time in tx, rx, idle, and power consumed) for the device.
+ */
+ ControllerActivityCounterImpl mWifiActivity;
- final LongSamplingCounter[] mWifiActivityCounters =
- new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+ /**
+ * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
+ */
+ ControllerActivityCounterImpl mBluetoothActivity;
+
+ /**
+ * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
+ */
+ ControllerActivityCounterImpl mModemActivity;
+
+ /**
+ * Whether the device supports WiFi controller energy reporting. This is set to true on
+ * the first WiFi energy report. See {@link #mWifiActivity}.
+ */
+ boolean mHasWifiReporting = false;
+
+ /**
+ * Whether the device supports Bluetooth controller energy reporting. This is set to true on
+ * the first Bluetooth energy report. See {@link #mBluetoothActivity}.
+ */
+ boolean mHasBluetoothReporting = false;
+
+ /**
+ * Whether the device supports Modem controller energy reporting. This is set to true on
+ * the first Modem energy report. See {@link #mModemActivity}.
+ */
+ boolean mHasModemReporting = false;
boolean mWifiOn;
StopwatchTimer mWifiOnTimer;
@@ -479,8 +513,6 @@
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
private PowerProfile mPowerProfile;
- private boolean mHasWifiEnergyReporting = false;
- private boolean mHasBluetoothEnergyReporting = false;
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
@@ -1770,6 +1802,131 @@
public abstract T instantiateObject();
}
+ public static class ControllerActivityCounterImpl extends ControllerActivityCounter
+ implements Parcelable {
+ private final LongSamplingCounter mIdleTimeMillis;
+ private final LongSamplingCounter mRxTimeMillis;
+ private final LongSamplingCounter[] mTxTimeMillis;
+ private final LongSamplingCounter mPowerDrainMaMs;
+
+ public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates) {
+ mIdleTimeMillis = new LongSamplingCounter(timeBase);
+ mRxTimeMillis = new LongSamplingCounter(timeBase);
+ mTxTimeMillis = new LongSamplingCounter[numTxStates];
+ for (int i = 0; i < numTxStates; i++) {
+ mTxTimeMillis[i] = new LongSamplingCounter(timeBase);
+ }
+ mPowerDrainMaMs = new LongSamplingCounter(timeBase);
+ }
+
+ public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates, Parcel in) {
+ mIdleTimeMillis = new LongSamplingCounter(timeBase, in);
+ mRxTimeMillis = new LongSamplingCounter(timeBase, in);
+ final int recordedTxStates = in.readInt();
+ if (recordedTxStates != numTxStates) {
+ throw new ParcelFormatException("inconsistent tx state lengths");
+ }
+
+ mTxTimeMillis = new LongSamplingCounter[numTxStates];
+ for (int i = 0; i < numTxStates; i++) {
+ mTxTimeMillis[i] = new LongSamplingCounter(timeBase, in);
+ }
+ mPowerDrainMaMs = new LongSamplingCounter(timeBase, in);
+ }
+
+ public void readSummaryFromParcel(Parcel in) {
+ mIdleTimeMillis.readSummaryFromParcelLocked(in);
+ mRxTimeMillis.readSummaryFromParcelLocked(in);
+ final int recordedTxStates = in.readInt();
+ if (recordedTxStates != mTxTimeMillis.length) {
+ throw new ParcelFormatException("inconsistent tx state lengths");
+ }
+ for (LongSamplingCounter counter : mTxTimeMillis) {
+ counter.readSummaryFromParcelLocked(in);
+ }
+ mPowerDrainMaMs.readSummaryFromParcelLocked(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeSummaryToParcel(Parcel dest) {
+ mIdleTimeMillis.writeSummaryFromParcelLocked(dest);
+ mRxTimeMillis.writeSummaryFromParcelLocked(dest);
+ dest.writeInt(mTxTimeMillis.length);
+ for (LongSamplingCounter counter : mTxTimeMillis) {
+ counter.writeSummaryFromParcelLocked(dest);
+ }
+ mPowerDrainMaMs.writeSummaryFromParcelLocked(dest);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mIdleTimeMillis.writeToParcel(dest);
+ mRxTimeMillis.writeToParcel(dest);
+ dest.writeInt(mTxTimeMillis.length);
+ for (LongSamplingCounter counter : mTxTimeMillis) {
+ counter.writeToParcel(dest);
+ }
+ mPowerDrainMaMs.writeToParcel(dest);
+ }
+
+ public void reset(boolean detachIfReset) {
+ mIdleTimeMillis.reset(detachIfReset);
+ mRxTimeMillis.reset(detachIfReset);
+ for (LongSamplingCounter counter : mTxTimeMillis) {
+ counter.reset(detachIfReset);
+ }
+ mPowerDrainMaMs.reset(detachIfReset);
+ }
+
+ public void detach() {
+ mIdleTimeMillis.detach();
+ mRxTimeMillis.detach();
+ for (LongSamplingCounter counter : mTxTimeMillis) {
+ counter.detach();
+ }
+ mPowerDrainMaMs.detach();
+ }
+
+ /**
+ * @return a LongSamplingCounter, measuring time spent in the idle state in
+ * milliseconds.
+ */
+ @Override
+ public LongSamplingCounter getIdleTimeCounter() {
+ return mRxTimeMillis;
+ }
+
+ /**
+ * @return a LongSamplingCounter, measuring time spent in the receive state in
+ * milliseconds.
+ */
+ @Override
+ public LongSamplingCounter getRxTimeCounter() {
+ return mRxTimeMillis;
+ }
+
+ /**
+ * @return a LongSamplingCounter[], measuring time spent in various transmit states in
+ * milliseconds.
+ */
+ @Override
+ public LongSamplingCounter[] getTxTimeCounters() {
+ return mTxTimeMillis;
+ }
+
+ /**
+ * @return a LongSamplingCounter, measuring power use in milli-ampere milliseconds (mAmS).
+ */
+ @Override
+ public LongSamplingCounter getPowerCounter() {
+ return mPowerDrainMaMs;
+ }
+ }
+
/*
* Get the wakeup reason counter, and create a new one if one
* doesn't already exist.
@@ -3198,7 +3355,7 @@
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
} else {
mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
- updateMobileRadioStateLocked(realElapsedRealtimeMs);
+ updateMobileRadioStateLocked(realElapsedRealtimeMs, null);
mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
@@ -4144,8 +4301,7 @@
// 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.
- final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
- updateMobileRadioStateLocked(elapsedRealtimeMs);
+ updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), null);
updateWifiStateLocked(null);
}
@@ -4328,26 +4484,34 @@
return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
}
- @Override public boolean hasBluetoothActivityReporting() {
- return mHasBluetoothEnergyReporting;
+ @Override
+ public ControllerActivityCounter getBluetoothControllerActivity() {
+ return mBluetoothActivity;
}
- @Override public long getBluetoothControllerActivity(int type, int which) {
- if (type >= 0 && type < mBluetoothActivityCounters.length) {
- return mBluetoothActivityCounters[type].getCountLocked(which);
- }
- return 0;
+ @Override
+ public ControllerActivityCounter getWifiControllerActivity() {
+ return mWifiActivity;
}
- @Override public boolean hasWifiActivityReporting() {
- return mHasWifiEnergyReporting;
+ @Override
+ public ControllerActivityCounter getModemControllerActivity() {
+ return mModemActivity;
}
- @Override public long getWifiControllerActivity(int type, int which) {
- if (type >= 0 && type < mWifiActivityCounters.length) {
- return mWifiActivityCounters[type].getCountLocked(which);
- }
- return 0;
+ @Override
+ public boolean hasBluetoothActivityReporting() {
+ return mHasBluetoothReporting;
+ }
+
+ @Override
+ public boolean hasWifiActivityReporting() {
+ return mHasWifiReporting;
+ }
+
+ @Override
+ public boolean hasModemActivityReporting() {
+ return mHasModemReporting;
}
@Override
@@ -4457,15 +4621,21 @@
/**
* The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
+ * Can be null if the UID has had no such activity.
*/
- LongSamplingCounter[] mWifiControllerTime =
- new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+ private ControllerActivityCounterImpl mWifiControllerActivity;
/**
* The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode.
+ * Can be null if the UID has had no such activity.
*/
- LongSamplingCounter[] mBluetoothControllerTime =
- new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+ private ControllerActivityCounterImpl mBluetoothControllerActivity;
+
+ /**
+ * The amount of time this uid has kept the Modem controller in idle, tx, and rx mode.
+ * Can be null if the UID has had no such activity.
+ */
+ private ControllerActivityCounterImpl mModemControllerActivity;
/**
* The CPU times we had at the last history details update.
@@ -4684,18 +4854,43 @@
}
}
- public void noteWifiControllerActivityLocked(int type, long timeMs) {
- if (mWifiControllerTime[type] == null) {
- mWifiControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase);
- }
- mWifiControllerTime[type].addCountLocked(timeMs);
+ @Override
+ public ControllerActivityCounter getWifiControllerActivity() {
+ return mWifiControllerActivity;
}
- public void noteBluetoothControllerActivityLocked(int type, long timeMs) {
- if (mBluetoothControllerTime[type] == null) {
- mBluetoothControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase);
+ @Override
+ public ControllerActivityCounter getBluetoothControllerActivity() {
+ return mBluetoothControllerActivity;
+ }
+
+ @Override
+ public ControllerActivityCounter getModemControllerActivity() {
+ return mModemControllerActivity;
+ }
+
+ public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
+ if (mWifiControllerActivity == null) {
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_BT_TX_LEVELS);
}
- mBluetoothControllerTime[type].addCountLocked(timeMs);
+ return mWifiControllerActivity;
+ }
+
+ public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
+ if (mBluetoothControllerActivity == null) {
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_BT_TX_LEVELS);
+ }
+ return mBluetoothControllerActivity;
+ }
+
+ public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
+ if (mModemControllerActivity == null) {
+ mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ ModemActivityInfo.TX_POWER_LEVELS);
+ }
+ return mModemControllerActivity;
}
public StopwatchTimer createAudioTurnedOnTimerLocked() {
@@ -5083,24 +5278,6 @@
return 0;
}
- @Override
- public long getWifiControllerActivity(int type, int which) {
- if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
- mWifiControllerTime[type] != null) {
- return mWifiControllerTime[type].getCountLocked(which);
- }
- return 0;
- }
-
- @Override
- public long getBluetoothControllerActivity(int type, int which) {
- if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
- mBluetoothControllerTime[type] != null) {
- return mBluetoothControllerTime[type].getCountLocked(which);
- }
- return 0;
- }
-
void initNetworkActivityLocked() {
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -5190,14 +5367,16 @@
mMobileRadioActiveCount.reset(false);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (mWifiControllerTime[i] != null) {
- mWifiControllerTime[i].reset(false);
- }
+ if (mWifiControllerActivity != null) {
+ mWifiControllerActivity.reset(false);
+ }
- if (mBluetoothControllerTime[i] != null) {
- mBluetoothControllerTime[i].reset(false);
- }
+ if (mBluetoothActivity != null) {
+ mBluetoothActivity.reset(false);
+ }
+
+ if (mModemActivity != null) {
+ mModemActivity.reset(false);
}
mUserCpuTime.reset(false);
@@ -5342,15 +5521,18 @@
}
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (mWifiControllerTime[i] != null) {
- mWifiControllerTime[i].detach();
- }
-
- if (mBluetoothControllerTime[i] != null) {
- mBluetoothControllerTime[i].detach();
- }
+ if (mWifiControllerActivity != null) {
+ mWifiControllerActivity.detach();
}
+
+ if (mBluetoothControllerActivity != null) {
+ mBluetoothControllerActivity.detach();
+ }
+
+ if (mModemControllerActivity != null) {
+ mModemControllerActivity.detach();
+ }
+
mPids.clear();
mUserCpuTime.detach();
@@ -5521,22 +5703,25 @@
out.writeInt(0);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (mWifiControllerTime[i] != null) {
- out.writeInt(1);
- mWifiControllerTime[i].writeToParcel(out);
- } else {
- out.writeInt(0);
- }
+ if (mWifiControllerActivity != null) {
+ out.writeInt(1);
+ mWifiControllerActivity.writeToParcel(out, 0);
+ } else {
+ out.writeInt(0);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (mBluetoothControllerTime[i] != null) {
- out.writeInt(1);
- mBluetoothControllerTime[i].writeToParcel(out);
- } else {
- out.writeInt(0);
- }
+ if (mBluetoothControllerActivity != null) {
+ out.writeInt(1);
+ mBluetoothControllerActivity.writeToParcel(out, 0);
+ } else {
+ out.writeInt(0);
+ }
+
+ if (mModemControllerActivity != null) {
+ out.writeInt(1);
+ mModemControllerActivity.writeToParcel(out, 0);
+ } else {
+ out.writeInt(0);
}
mUserCpuTime.writeToParcel(out);
@@ -5727,20 +5912,25 @@
mNetworkPacketActivityCounters = null;
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (in.readInt() != 0) {
- mWifiControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
- } else {
- mWifiControllerTime[i] = null;
- }
+ if (in.readInt() != 0) {
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_WIFI_TX_LEVELS, in);
+ } else {
+ mWifiControllerActivity = null;
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- if (in.readInt() != 0) {
- mBluetoothControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
- } else {
- mBluetoothControllerTime[i] = null;
- }
+ if (in.readInt() != 0) {
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_BT_TX_LEVELS, in);
+ } else {
+ mBluetoothControllerActivity = null;
+ }
+
+ if (in.readInt() != 0) {
+ mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ ModemActivityInfo.TX_POWER_LEVELS, in);
+ } else {
+ mModemControllerActivity = null;
}
mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
@@ -6916,10 +7106,12 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- }
+ mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
+ mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_BT_TX_LEVELS);
+ mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ ModemActivityInfo.TX_POWER_LEVELS);
+
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -7567,10 +7759,9 @@
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].reset(false);
}
- for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i].reset(false);
- mWifiActivityCounters[i].reset(false);
- }
+ mWifiActivity.reset(false);
+ mBluetoothActivity.reset(false);
+ mModemActivity.reset(false);
mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) {
@@ -7781,7 +7972,7 @@
}
if (info != null) {
- mHasWifiEnergyReporting = true;
+ mHasWifiReporting = true;
// Measured in mAms
final long txTimeMs = info.getControllerTxTimeMillis();
@@ -7861,8 +8052,11 @@
+ scanRxTimeSinceMarkMs + " ms Tx:"
+ scanTxTimeSinceMarkMs + " ms)");
}
- uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanRxTimeSinceMarkMs);
- uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, scanTxTimeSinceMarkMs);
+
+ ControllerActivityCounterImpl activityCounter =
+ uid.getOrCreateWifiControllerActivityLocked();
+ activityCounter.getRxTimeCounter().addCountLocked(scanRxTimeSinceMarkMs);
+ activityCounter.getTxTimeCounters()[0].addCountLocked(scanTxTimeSinceMarkMs);
leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
}
@@ -7881,7 +8075,8 @@
Slog.d(TAG, " IdleTime for UID " + uid.getUid() + ": "
+ myIdleTimeMs + " ms");
}
- uid.noteWifiControllerActivityLocked(CONTROLLER_IDLE_TIME, myIdleTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
+ .addCountLocked(myIdleTimeMs);
}
}
@@ -7898,7 +8093,8 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, " TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
}
- uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, myTxTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
+ .addCountLocked(myTxTimeMs);
}
// Distribute the remaining Rx power appropriately between all apps that received
@@ -7909,25 +8105,23 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, " RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
}
- uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, myRxTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
+ .addCountLocked(myRxTimeMs);
}
// Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
// 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());
+ mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
+ mWifiActivity.getTxTimeCounters()[0].addCountLocked(info.getControllerTxTimeMillis());
+ mWifiActivity.getIdleTimeCounter().addCountLocked(info.getControllerIdleTimeMillis());
// POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
if (opVolt != 0) {
// We store the power drain as mAms.
- mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+ mWifiActivity.getPowerCounter().addCountLocked(
(long)(info.getControllerEnergyUsed() / opVolt));
}
}
@@ -7936,9 +8130,10 @@
/**
* Distribute Cell radio energy info and network traffic to apps.
*/
- public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) {
+ public void updateMobileRadioStateLocked(final long elapsedRealtimeMs,
+ final ModemActivityInfo activityInfo) {
if (DEBUG_ENERGY) {
- Slog.d(TAG, "Updating mobile radio stats");
+ Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
NetworkStats delta = null;
@@ -7951,60 +8146,112 @@
return;
}
- if (delta == null || !mOnBatteryInternal) {
+ if (!mOnBatteryInternal) {
return;
}
long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
mMobileRadioActivePerAppTimer.setMark(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);
+ long totalRxPackets = 0;
+ long totalTxPackets = 0;
+ if (delta != null) {
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+ if (entry.rxPackets == 0 && entry.txPackets == 0) {
+ continue;
+ }
- if (entry.rxBytes == 0 || entry.txBytes == 0) {
- continue;
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+ + " txPackets=" + entry.txPackets);
+ }
+
+ totalRxPackets += entry.rxPackets;
+ totalTxPackets += entry.txPackets;
+
+ 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);
+
+ 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 (DEBUG_ENERGY) {
- Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
- + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
- + " txPackets=" + entry.txPackets);
- }
+ // Now distribute proportional blame to the apps that did networking.
+ long totalPackets = totalRxPackets + totalTxPackets;
+ if (totalPackets > 0) {
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+ if (entry.rxPackets == 0 && entry.txPackets == 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);
+ final Uid u = getUidStatsLocked(mapUid(entry.uid));
+
+ // Distribute total radio active time in to this app.
+ final long appPackets = entry.rxPackets + entry.txPackets;
+ final 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;
+
+ if (activityInfo != null) {
+ ControllerActivityCounterImpl activityCounter =
+ u.getOrCreateModemControllerActivityLocked();
+ if (totalRxPackets > 0 && entry.rxPackets > 0) {
+ final long rxMs = (entry.rxPackets * activityInfo.getRxTimeMillis())
+ / totalRxPackets;
+ activityCounter.getRxTimeCounter().addCountLocked(rxMs);
+ }
+
+ if (totalTxPackets > 0 && entry.txPackets > 0) {
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ long txMs = entry.txPackets * activityInfo.getTxTimeMillis()[lvl];
+ txMs /= totalTxPackets;
+ activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
+ }
+ }
+ }
+ }
+ }
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;
+ // Whoops, there is some radio time we can't blame on an app!
+ mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+ mMobileRadioActiveUnknownCount.addCountLocked(1);
}
-
- 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 (activityInfo != null) {
+ mHasModemReporting = true;
+ mModemActivity.getIdleTimeCounter().addCountLocked(activityInfo.getIdleTimeMillis());
+ mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ mModemActivity.getTxTimeCounters()[lvl]
+ .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
+ }
+
+ // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
+ final double opVolt = mPowerProfile.getAveragePower(
+ PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
+ if (opVolt != 0) {
+ // We store the power drain as mAms.
+ mModemActivity.getPowerCounter().addCountLocked(
+ (long) (activityInfo.getEnergyUsed() / opVolt));
+ }
}
}
@@ -8018,12 +8265,12 @@
}
if (info != null && mOnBatteryInternal) {
- mHasBluetoothEnergyReporting = true;
- mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+ mHasBluetoothReporting = true;
+ mBluetoothActivity.getRxTimeCounter().addCountLocked(
info.getControllerRxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+ mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
info.getControllerTxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+ mBluetoothActivity.getIdleTimeCounter().addCountLocked(
info.getControllerIdleTimeMillis());
// POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -8031,7 +8278,7 @@
PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
if (opVolt != 0) {
// We store the power drain as mAms.
- mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+ mBluetoothActivity.getPowerCounter().addCountLocked(
(long) (info.getControllerEnergyUsed() / opVolt));
}
@@ -9337,12 +9584,12 @@
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
- }
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
- }
+ mWifiActivity.readSummaryFromParcel(in);
+ mBluetoothActivity.readSummaryFromParcel(in);
+ mModemActivity.readSummaryFromParcel(in);
+ mHasWifiReporting = in.readInt() != 0;
+ mHasBluetoothReporting = in.readInt() != 0;
+ mHasModemReporting = in.readInt() != 0;
mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
mFlashlightOnNesting = 0;
@@ -9671,12 +9918,13 @@
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
- for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
- }
- for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
- }
+ mWifiActivity.writeSummaryToParcel(out);
+ mBluetoothActivity.writeSummaryToParcel(out);
+ mModemActivity.writeSummaryToParcel(out);
+ out.writeInt(mHasWifiReporting ? 1 : 0);
+ out.writeInt(mHasBluetoothReporting ? 1 : 0);
+ out.writeInt(mHasModemReporting ? 1 : 0);
+
out.writeInt(mNumConnectivityChange);
mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -10019,15 +10267,17 @@
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
null, mOnBatteryTimeBase, in);
}
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
- }
- for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
- }
- mHasWifiEnergyReporting = in.readInt() != 0;
- mHasBluetoothEnergyReporting = in.readInt() != 0;
+ mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_WIFI_TX_LEVELS, in);
+ mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ NUM_BT_TX_LEVELS, in);
+ mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ ModemActivityInfo.TX_POWER_LEVELS, in);
+ mHasWifiReporting = in.readInt() != 0;
+ mHasBluetoothReporting = in.readInt() != 0;
+ mHasModemReporting = in.readInt() != 0;
+
mNumConnectivityChange = in.readInt();
mLoadedNumConnectivityChange = in.readInt();
mUnpluggedNumConnectivityChange = in.readInt();
@@ -10174,14 +10424,13 @@
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
- for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mBluetoothActivityCounters[i].writeToParcel(out);
- }
- for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
- mWifiActivityCounters[i].writeToParcel(out);
- }
- out.writeInt(mHasWifiEnergyReporting ? 1 : 0);
- out.writeInt(mHasBluetoothEnergyReporting ? 1 : 0);
+ mWifiActivity.writeToParcel(out, 0);
+ mBluetoothActivity.writeToParcel(out, 0);
+ mModemActivity.writeToParcel(out, 0);
+ out.writeInt(mHasWifiReporting ? 1 : 0);
+ out.writeInt(mHasBluetoothReporting ? 1 : 0);
+ out.writeInt(mHasModemReporting ? 1 : 0);
+
out.writeInt(mNumConnectivityChange);
out.writeInt(mLoadedNumConnectivityChange);
out.writeInt(mUnpluggedNumConnectivityChange);
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 1f59672..531d1fa 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -40,15 +40,15 @@
@Override
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final long idleTimeMs = stats.getBluetoothControllerActivity(
- BatteryStats.CONTROLLER_IDLE_TIME, statsType);
- final long txTimeMs = stats.getBluetoothControllerActivity(
- BatteryStats.CONTROLLER_TX_TIME, statsType);
- final long rxTimeMs = stats.getBluetoothControllerActivity(
- BatteryStats.CONTROLLER_RX_TIME, statsType);
+ final BatteryStats.ControllerActivityCounter counter =
+ stats.getBluetoothControllerActivity();
+
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
- double powerMah = stats.getBluetoothControllerActivity(
- BatteryStats.CONTROLLER_POWER_DRAIN, statsType) / (double)(1000*60*60);
+ double powerMah = counter.getPowerCounter().getCountLocked(statsType)
+ / (double)(1000*60*60);
if (powerMah == 0) {
// Some devices do not report the power, so calculate it.
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index aaa9f73..14ebe22 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -93,6 +93,12 @@
public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
"bluetooth.controller.voltage";
+ public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle";
+ public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx";
+ public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx";
+ public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE =
+ "modem.controller.voltage";
+
/**
* Power consumption when GPS is on.
*/
@@ -100,17 +106,23 @@
/**
* Power consumption when Bluetooth driver is on.
+ * @deprecated
*/
+ @Deprecated
public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
/**
* Power consumption when Bluetooth driver is transmitting/receiving.
+ * @deprecated
*/
+ @Deprecated
public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
/**
* Power consumption when Bluetooth driver gets an AT command.
+ * @deprecated
*/
+ @Deprecated
public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index f81658e..3b8b7cb 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -86,6 +86,13 @@
Clog_e(TAG, message.toString(), e);
}
+ // Try to end profiling. If a profiler is running at this point, and we kill the
+ // process (below), the in-memory buffer will be lost. So try to stop, which will
+ // flush the buffer. (This makes method trace profiling useful to debug crashes.)
+ if (ActivityThread.currentActivityThread() != null) {
+ ActivityThread.currentActivityThread().stopProfiling();
+ }
+
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 146c0f8..2a27f70 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -39,10 +39,14 @@
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final long idleTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
- statsType);
- final long txTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, statsType);
- final long rxTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, statsType);
+ final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
+ if (counter == null) {
+ return;
+ }
+
+ final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
app.wifiRunningTimeMs = idleTime + rxTime + txTime;
app.wifiPowerMah =
((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
@@ -67,16 +71,15 @@
@Override
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final long idleTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
- statsType);
- final long rxTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME,
- statsType);
- final long txTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME,
- statsType);
+ final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
+
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs;
- double powerDrainMah = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN,
- statsType) / (double)(1000*60*60);
+ double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
+ / (double)(1000*60*60);
if (powerDrainMah == 0) {
// Some controllers do not report power drain, so we can calculate it here.
powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a572486..a38139f 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -139,7 +139,12 @@
}
public SnapTarget getClosestDismissTarget(int position) {
- if (position - mDismissStartTarget.position < mDismissEndTarget.position - position) {
+ if (position < mFirstSplitTarget.position) {
+ return mDismissStartTarget;
+ } else if (position > mLastSplitTarget.position) {
+ return mDismissEndTarget;
+ } else if (position - mDismissStartTarget.position
+ < mDismissEndTarget.position - position) {
return mDismissStartTarget;
} else {
return mDismissEndTarget;
diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java
index f7f5f15..00c65bd 100644
--- a/core/java/com/android/internal/policy/DockedDividerUtils.java
+++ b/core/java/com/android/internal/policy/DockedDividerUtils.java
@@ -48,17 +48,21 @@
outRect.top = position + dividerSize;
break;
}
- if (outRect.left >= outRect.right) {
- outRect.left = outRect.right - 1;
+ sanitizeStackBounds(outRect);
+ }
+
+ public static void sanitizeStackBounds(Rect bounds) {
+ if (bounds.left >= bounds.right) {
+ bounds.left = bounds.right - 1;
}
- if (outRect.top >= outRect.bottom) {
- outRect.top = outRect.bottom - 1;
+ if (bounds.top >= bounds.bottom) {
+ bounds.top = bounds.bottom - 1;
}
- if (outRect.right <= outRect.left) {
- outRect.right = outRect.left + 1;
+ if (bounds.right <= bounds.left) {
+ bounds.right = bounds.left + 1;
}
- if (outRect.bottom <= outRect.top) {
- outRect.bottom = outRect.top + 1;
+ if (bounds.bottom <= bounds.top) {
+ bounds.bottom = bounds.top + 1;
}
}
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index b4d2d730..968d920 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -97,6 +97,21 @@
}
/**
+ * Primitive float version of {@link #append(Object[], int, Object)}.
+ */
+ public static float[] append(float[] array, int currentSize, float element) {
+ assert currentSize <= array.length;
+
+ if (currentSize + 1 > array.length) {
+ float[] newArray = ArrayUtils.newUnpaddedFloatArray(growSize(currentSize));
+ System.arraycopy(array, 0, newArray, 0, currentSize);
+ array = newArray;
+ }
+ array[currentSize] = element;
+ return array;
+ }
+
+ /**
* Inserts an element into the array at the specified index, growing the array if there is no
* more room.
*
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 7dfc15d..bcc310f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -38,7 +38,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
- Rect backDropFrame) {
+ Rect backDropFrame, boolean forceLayout) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 3a00469..480d806 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -920,14 +920,14 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- if (hasOverflow()) {
- // overflow not open. Set closed state.
- final Size containerSize = mMainPanelSize;
- setSize(mContentContainer, containerSize);
- mMainPanel.setAlpha(1);
- mOverflowPanel.setAlpha(0);
- mOverflowButton.setImageDrawable(mOverflow);
+ // Overflow not open. Set closed state.
+ final Size containerSize = mMainPanelSize;
+ setSize(mContentContainer, containerSize);
+ mMainPanel.setAlpha(1);
+ mOverflowPanel.setAlpha(0);
+ mOverflowButton.setImageDrawable(mOverflow);
+ if (hasOverflow()) {
// Update x-coordinates depending on RTL state.
if (isRTL()) {
mContentContainer.setX(mMarginHorizontal); // align left
@@ -960,8 +960,11 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- mContentContainer.setX(mMarginHorizontal);
- mContentContainer.setY(mMarginVertical);
+ // No overflow.
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setX(0); // align left
+ mMainPanel.setY(0); // align top
}
}
}
@@ -1092,6 +1095,7 @@
final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
mMainPanel.removeAllViews();
+ mMainPanel.setPaddingRelative(0, 0, 0, 0);
boolean isFirstItem = true;
while (!remainingMenuItems.isEmpty()) {
@@ -1264,7 +1268,7 @@
}
private void maybeComputeTransitionDurationScale() {
- if (mMainPanelSize == null || mOverflowPanel == null) {
+ if (mMainPanelSize != null && mOverflowPanelSize != null) {
int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth();
int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight();
mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h) /
@@ -1302,7 +1306,6 @@
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final Drawable drawable = overflowButton.getDrawable();
if (mIsOverflowOpen) {
overflowButton.setImageDrawable(mToOverflow);
mToOverflow.start();
@@ -1599,6 +1602,8 @@
private static ViewGroup createContentContainer(Context context) {
ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_container, null);
+ contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentContainer.setTag(FLOATING_TOOLBAR_TAG);
return contentContainer;
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..b07e36a 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -39,4 +39,5 @@
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
+ void systemReady();
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3f468ac..ba456f9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,7 +17,6 @@
package com.android.internal.widget;
import android.annotation.IntDef;
-import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -503,10 +502,9 @@
if (userHandle == UserHandle.USER_SYSTEM) {
// Set the encryption password to default.
updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ setCredentialRequiredToDecrypt(false);
}
- setCredentialRequiredToDecrypt(false);
-
getDevicePolicyManager().setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
@@ -1340,9 +1338,9 @@
}
public void setCredentialRequiredToDecrypt(boolean required) {
- if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
- Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
- return;
+ if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
+ throw new IllegalStateException(
+ "Only the system or primary user may call setCredentialRequiredForDecrypt()");
}
if (isDeviceEncryptionEnabled()){
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
new file mode 100644
index 0000000..b45fd06
--- /dev/null
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A TextView that can float around an image on the end.
+ *
+ * @hide
+ */
+@RemoteViews.RemoteView
+public class MediaNotificationView extends RelativeLayout {
+
+ private final int mMaxImageSize;
+ private final int mImageMarginBottom;
+ private final int mImageMinTopMargin;
+ private final int mNotificationContentMarginEnd;
+ private final int mNotificationContentImageMarginEnd;
+ private ImageView mRightIcon;
+ private View mActions;
+ private View mHeader;
+
+ public MediaNotificationView(Context context) {
+ this(context, null);
+ }
+
+ public MediaNotificationView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MediaNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int mode = MeasureSpec.getMode(widthMeasureSpec);
+ boolean hasIcon = mRightIcon.getVisibility() != GONE;
+ if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
+ measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
+ int size = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ size = size - mActions.getMeasuredWidth();
+ ViewGroup.MarginLayoutParams layoutParams =
+ (MarginLayoutParams) mRightIcon.getLayoutParams();
+ size -= layoutParams.getMarginEnd();
+ size = Math.min(size, mMaxImageSize);
+ size = Math.max(size, mRightIcon.getMinimumWidth());
+ layoutParams.width = size;
+ layoutParams.height = size;
+ // because we can't allign it to the bottom with a margin, we add a topmargin to it
+ layoutParams.topMargin = height - size - mImageMarginBottom;
+ // If the topMargin is high enough we can also remove the header constraint!
+ if (layoutParams.topMargin >= mImageMinTopMargin) {
+ resetHeaderIndention();
+ } else {
+ int paddingEnd = mNotificationContentImageMarginEnd;
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(size + layoutParams.getMarginEnd());
+ if (mHeader.getPaddingEnd() != paddingEnd) {
+ mHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
+ mRightIcon.setLayoutParams(layoutParams);
+ } else if (!hasIcon && mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+ resetHeaderIndention();
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private void resetHeaderIndention() {
+ if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(0);
+ mHeader.setPadding(
+ isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
+
+ public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mMaxImageSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.media_notification_expanded_image_max_size);
+ mImageMarginBottom = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.media_notification_expanded_image_margin_bottom);
+ mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_top)
+ + getResources().getDisplayMetrics().density * 2);
+ mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
+ mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_image_margin_end);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
+ mActions = findViewById(com.android.internal.R.id.media_actions);
+ mHeader = findViewById(com.android.internal.R.id.notification_header);
+ }
+}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 53d4c6a..563ec8b 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -90,6 +90,18 @@
strokeLineJoin);
}
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ path->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ path->setStrokeGradient(strokeShader);
+}
+
static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
jbyteArray outProperties, jint length) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
@@ -331,6 +343,8 @@
{"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
{"nCreateFullPath", "!(J)J", (void*)createFullPath},
{"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
+ {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
{"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
{"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 414eba7..806fcc3 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -534,7 +534,7 @@
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
// Default path: hal version is don't care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
- Camera::USE_CALLING_UID);
+ Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
} else {
jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
Camera::USE_CALLING_UID, camera);
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 2e5cda0..4842e1b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
#include <utils/Looper.h>
+#include <utils/Vector.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
@@ -39,12 +40,14 @@
jclass clazz;
jmethodID dispatchSensorEvent;
jmethodID dispatchFlushCompleteEvent;
+ jmethodID dispatchAdditionalInfoEvent;
} gBaseEventQueueClassInfo;
namespace android {
struct SensorOffsets
{
+ jclass clazz;
jfieldID name;
jfieldID vendor;
jfieldID version;
@@ -60,8 +63,13 @@
jfieldID maxDelay;
jfieldID flags;
jmethodID setType;
+ jmethodID init;
} gSensorOffsets;
+struct ListOffsets {
+ jclass clazz;
+ jmethodID add;
+} gListOffsets;
/*
* The method below are not thread-safe and not intended to be
@@ -70,8 +78,10 @@
static void
nativeClassInit (JNIEnv *_env, jclass _this)
{
- jclass sensorClass = _env->FindClass("android/hardware/Sensor");
+ //android.hardware.Sensor
SensorOffsets& sensorOffsets = gSensorOffsets;
+ jclass sensorClass = (jclass) _env->NewGlobalRef(_env->FindClass("android/hardware/Sensor"));
+ sensorOffsets.clazz = sensorClass;
sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;");
sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;");
sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I");
@@ -88,7 +98,15 @@
"Ljava/lang/String;");
sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
+
sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+ sensorOffsets.init = _env->GetMethodID(sensorClass, "<init>", "()V");
+
+ // java.util.List;
+ ListOffsets& listOffsets = gListOffsets;
+ jclass listClass = (jclass) _env->NewGlobalRef(_env->FindClass("java/util/List"));
+ listOffsets.clazz = listClass;
+ listOffsets.add = _env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
}
/**
@@ -141,6 +159,46 @@
return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
}
+static jobject
+translateNativeSensorToJavaSensor(JNIEnv *env, jobject sensor, const Sensor& nativeSensor) {
+ const SensorOffsets& sensorOffsets(gSensorOffsets);
+
+ if (sensor == NULL) {
+ // Sensor sensor = new Sensor();
+ sensor = env->NewObject(sensorOffsets.clazz, sensorOffsets.init, "");
+ }
+
+ if (sensor != NULL) {
+ jstring name = env->NewStringUTF(nativeSensor.getName().string());
+ jstring vendor = env->NewStringUTF(nativeSensor.getVendor().string());
+ jstring requiredPermission =
+ env->NewStringUTF(nativeSensor.getRequiredPermission().string());
+
+ env->SetObjectField(sensor, sensorOffsets.name, name);
+ env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
+ env->SetIntField(sensor, sensorOffsets.version, nativeSensor.getVersion());
+ env->SetIntField(sensor, sensorOffsets.handle, nativeSensor.getHandle());
+ env->SetFloatField(sensor, sensorOffsets.range, nativeSensor.getMaxValue());
+ env->SetFloatField(sensor, sensorOffsets.resolution, nativeSensor.getResolution());
+ env->SetFloatField(sensor, sensorOffsets.power, nativeSensor.getPowerUsage());
+ env->SetIntField(sensor, sensorOffsets.minDelay, nativeSensor.getMinDelay());
+ env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
+ nativeSensor.getFifoReservedEventCount());
+ env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+ nativeSensor.getFifoMaxEventCount());
+ env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+ requiredPermission);
+ env->SetIntField(sensor, sensorOffsets.maxDelay, nativeSensor.getMaxDelay());
+ env->SetIntField(sensor, sensorOffsets.flags, nativeSensor.getFlags());
+ if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
+ == JNI_FALSE) {
+ jstring stringType = getInternedString(env, &nativeSensor.getStringType());
+ env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+ }
+ }
+ return sensor;
+}
+
static jboolean
nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
{
@@ -180,6 +238,24 @@
return true;
}
+static void
+nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensorList) {
+
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ const ListOffsets& listOffsets(gListOffsets);
+
+ Vector<Sensor> nativeList;
+
+ mgr->getDynamicSensorList(nativeList);
+
+ ALOGI("DYNS native SensorManager.getDynamicSensorList return %d sensors", nativeList.size());
+ for (size_t i = 0; i < nativeList.size(); ++i) {
+ jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
+ // add to list
+ env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
+ }
+}
+
static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
return mgr->isDataInjectionEnabled();
@@ -191,21 +267,25 @@
sp<SensorEventQueue> mSensorQueue;
sp<MessageQueue> mMessageQueue;
jobject mReceiverWeakGlobal;
- jfloatArray mScratch;
+ jfloatArray mFloatScratch;
+ jintArray mIntScratch;
public:
Receiver(const sp<SensorEventQueue>& sensorQueue,
const sp<MessageQueue>& messageQueue,
- jobject receiverWeak, jfloatArray scratch) {
+ jobject receiverWeak) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
mSensorQueue = sensorQueue;
mMessageQueue = messageQueue;
mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
- mScratch = (jfloatArray)env->NewGlobalRef(scratch);
+
+ mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
+ mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
}
~Receiver() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverWeakGlobal);
- env->DeleteGlobalRef(mScratch);
+ env->DeleteGlobalRef(mFloatScratch);
+ env->DeleteGlobalRef(mIntScratch);
}
sp<SensorEventQueue> getSensorEventQueue() const {
return mSensorQueue;
@@ -234,9 +314,19 @@
if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
// step-counter returns a uint64, but the java API only deals with floats
float value = float(buffer[i].u64.step_counter);
- env->SetFloatArrayRegion(mScratch, 0, 1, &value);
+ env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
+ } else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+ float value[2];
+ value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
+ value[1] = float(buffer[i].dynamic_sensor_meta.handle);
+ env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
+ } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+ env->SetIntArrayRegion(mIntScratch, 0, 14,
+ buffer[i].additional_info.data_int32);
+ env->SetFloatArrayRegion(mFloatScratch, 0, 14,
+ buffer[i].additional_info.data_float);
} else {
- env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
+ env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
}
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
@@ -247,7 +337,21 @@
gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
buffer[i].meta_data.sensor);
}
- } else {
+ } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+ // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
+ // method.
+ if (receiverObj.get()) {
+ int type = buffer[i].additional_info.type;
+ int serial = buffer[i].additional_info.serial;
+ env->CallVoidMethod(receiverObj.get(),
+ gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
+ buffer[i].sensor,
+ type, serial,
+ mFloatScratch,
+ mIntScratch,
+ buffer[i].timestamp);
+ }
+ }else {
int8_t status;
switch (buffer[i].type) {
case SENSOR_TYPE_ORIENTATION:
@@ -269,7 +373,7 @@
env->CallVoidMethod(receiverObj.get(),
gBaseEventQueueClassInfo.dispatchSensorEvent,
buffer[i].sensor,
- mScratch,
+ mFloatScratch,
status,
buffer[i].timestamp);
}
@@ -290,7 +394,7 @@
};
static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
- jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName, jint mode) {
+ jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
ScopedUtfChars packageUtf(env, packageName);
String8 clientName(packageUtf.c_str());
@@ -302,7 +406,7 @@
return 0;
}
- sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak, scratch);
+ sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
receiver->incStrong((void*)nativeInitSensorEventQueue);
return jlong(receiver.get());
}
@@ -355,6 +459,10 @@
"(JLandroid/hardware/Sensor;I)Z",
(void*)nativeGetSensorAtIndex },
+ {"nativeGetDynamicSensors",
+ "(JLjava/util/List;)V",
+ (void*)nativeGetDynamicSensors },
+
{"nativeIsDataInjectionEnabled",
"(J)Z",
(void*)nativeIsDataInjectionEnabled},
@@ -362,7 +470,7 @@
static const JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
- "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
+ "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
(void*)nativeInitSensorEventQueue },
{"nativeEnableSensor",
@@ -407,5 +515,8 @@
gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
+ gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
+ gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
+
return 0;
}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index b977e37..d25da78 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -54,6 +54,10 @@
};
static audio_attributes_fields_t javaAudioAttrFields;
static audio_record_fields_t javaAudioRecordFields;
+static struct {
+ jfieldID fieldFramePosition; // AudioTimestamp.framePosition
+ jfieldID fieldNanoTime; // AudioTimestamp.nanoTime
+} javaAudioTimestampFields;
struct audiorecord_callback_cookie {
jclass audioRecord_class;
@@ -678,7 +682,40 @@
}
}
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
+ jobject timestamp, jint timebase) {
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for getTimestamp()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ // TODO Enable.
+#if 0
+ // get the record timestamp
+ ExtendedTimestamp ts;
+ jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));
+
+ if (status == AUDIO_JAVA_SUCCESS) {
+ // set the data
+ int64_t position, time;
+
+ status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
+ if (status == AUDIO_JAVA_SUCCESS) {
+ env->SetLongField(
+ timestamp, javaAudioTimestampFields.fieldFramePosition, position);
+ env->SetLongField(
+ timestamp, javaAudioTimestampFields.fieldNanoTime, time);
+ }
+ }
+ return status;
+#else
+ return (jint)AUDIO_JAVA_INVALID_OPERATION;
+#endif
+}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -716,6 +753,8 @@
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
(void *)android_media_AudioRecord_disableDeviceCallback},
+ {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+ (void *)android_media_AudioRecord_get_timestamp},
};
// field names found in android/media/AudioRecord.java
@@ -758,6 +797,13 @@
javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
+ // Get the RecordTimestamp class and fields
+ jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
+ javaAudioTimestampFields.fieldFramePosition =
+ GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
+ javaAudioTimestampFields.fieldNanoTime =
+ GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
+
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 041e693..4194aa4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -608,7 +608,7 @@
jlong capabilities = 0;
// Grant CAP_WAKE_ALARM to the Bluetooth process.
- if (uid == AID_BLUETOOTH) {
+ if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 56c3fc8..c970989 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -420,6 +420,8 @@
<protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
<protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
+ <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -722,7 +724,7 @@
android:protectionLevel="dangerous" />
<!-- Allows an application to write (but not read) the user's
- contacts data.
+ call log data.
<p class="note"><strong>Note:</strong> If your app uses the
{@link #WRITE_CONTACTS} permission and <em>both</em> your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
@@ -1407,6 +1409,13 @@
<permission android:name="android.permission.BIND_INCALL_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by a {@link android.telecom.CallScreeningService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_SCREENING_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
@deprecated {@link android.telecom.ConnectionService}s should require
@@ -2860,6 +2869,12 @@
<permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by system/priv apps when accessing the sound trigger
+ APIs given by {@link SoundTriggerManager}.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
new file mode 100644
index 0000000..e8169ee
--- /dev/null
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/dialog_list_padding_vertical_material"
+ android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+
+ <TextView
+ android:id="@+id/aerr_close"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/aerr_close_app"
+ style="@style/aerr_list_item" />
+
+ <TextView
+ android:id="@+id/aerr_wait"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/aerr_wait"
+ style="@style/aerr_list_item" />
+
+ <TextView
+ android:id="@+id/aerr_report"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/aerr_report"
+ style="@style/aerr_list_item" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index aaa2dbc..46a2b2a 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -26,7 +26,7 @@
>
- <TextView
+ <Button
android:id="@+id/aerr_restart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -34,7 +34,7 @@
style="@style/aerr_list_item"
/>
- <TextView
+ <Button
android:id="@+id/aerr_reset"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -42,7 +42,7 @@
style="@style/aerr_list_item"
/>
- <TextView
+ <Button
android:id="@+id/aerr_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -50,7 +50,7 @@
style="@style/aerr_list_item"
/>
- <TextView
+ <Button
android:id="@+id/aerr_close"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -58,7 +58,7 @@
style="@style/aerr_list_item"
/>
- <TextView
+ <Button
android:id="@+id/aerr_mute"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index e8ff186..aa78eff 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -16,17 +16,17 @@
-->
<!-- Layout for the expanded media notification -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.MediaNotificationView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
- android:layout_height="128dp"
+ android:layout_height="126dp"
android:background="#00000000"
android:tag="bigMediaNarrow"
>
<include layout="@layout/notification_template_header"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="48dp"
- android:layout_marginEnd="106dp"/>
+ android:layout_alignParentStart="true"/>
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
@@ -34,7 +34,7 @@
android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:layout_marginEnd="24dp"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_toStartOf="@id/right_icon"
android:minHeight="@dimen/notification_min_content_height"
android:orientation="vertical"
@@ -57,12 +57,13 @@
</LinearLayout>
<ImageView android:id="@+id/right_icon"
- android:layout_width="96dp"
- android:layout_height="96dp"
+ android:layout_width="@dimen/media_notification_expanded_image_max_size"
+ android:layout_height="@dimen/media_notification_expanded_image_max_size"
+ android:minWidth="40dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
/>
-</RelativeLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 9fcd356..aea9b44 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -24,8 +24,7 @@
>
<include layout="@layout/notification_template_header"
android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_marginEnd="106dp"/>
+ android:layout_height="48dp" />
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
@@ -34,7 +33,6 @@
android:orientation="horizontal"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginTop="@dimen/notification_content_margin_top"
- android:layout_marginEnd="72dp"
android:tag="media"
>
<LinearLayout
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index fe02d4e..17e93d0 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -14,32 +14,41 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="@drawable/text_edit_suggestions_window"
- android:dropDownSelector="@drawable/list_selector_background"
- android:divider="@null">
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:divider="?android:attr/dividerHorizontal">
- <!-- Suggestions will be added here. -->
- </ListView>
-
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="middle">
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:background="@drawable/text_edit_suggestions_window"
+ android:dropDownSelector="@drawable/list_selector_background"
+ android:divider="@null">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="?android:attr/dividerHorizontal">
+ <!-- Suggestions will be added here. -->
+ </ListView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 62e315b4..7826803 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -16,29 +16,38 @@
<!-- Background of the popup window is the same as the one of the floating toolbar.
Use floating toolbar background style. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:divider="?android:attr/listDivider"
- android:showDividers="middle" >
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dip"
- android:paddingBottom="0dip"
- android:divider="@null" />
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:orientation="vertical"
+ android:divider="?android:attr/listDivider"
+ android:showDividers="middle">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="0dp"
+ android:divider="@null" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 713038b..1f7206e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3727,7 +3727,7 @@
<!-- Controls how the image should be resized or moved to match the size
of this ImageView. See {@link android.widget.ImageView.ScaleType} -->
<attr name="scaleType">
- <!-- Scale using the image matrix when drawing. See
+ <!-- Scale using the image matrix when drawing. See
{@link android.widget.ImageView#setImageMatrix(Matrix)}. -->
<enum name="matrix" value="0" />
<!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#FILL}. -->
@@ -3740,7 +3740,7 @@
<enum name="fitEnd" value="4" />
<!-- Center the image in the view, but perform no scaling. -->
<enum name="center" value="5" />
- <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
+ <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
(width and height) of the image will be equal to or larger than the corresponding
dimension of the view (minus padding). The image is then centered in the view. -->
<enum name="centerCrop" value="6" />
@@ -8135,4 +8135,52 @@
<attr name="entries" />
<attr name="entryValues" />
</declare-styleable>
+
+ <!-- Used to describe the gradient for fill or stroke in a path of VectorDrawable. -->
+ <declare-styleable name="GradientColor">
+ <!-- Start color of the gradient. -->
+ <attr name="startColor" />
+ <!-- Optional center color. -->
+ <attr name="centerColor" />
+ <!-- End color of the gradient. -->
+ <attr name="endColor" />
+ <!-- Type of gradient. The default type is linear. -->
+ <attr name="type" />
+
+ <!-- Only applied to RadialGradient-->
+ <!-- Radius of the gradient, used only with radial gradient. -->
+ <attr name="gradientRadius" />
+
+ <!-- Only applied to SweepGradient / RadialGradient-->
+ <!-- X coordinate of the center of the gradient within the path. -->
+ <attr name="centerX" />
+ <!-- Y coordinate of the center of the gradient within the path. -->
+ <attr name="centerY" />
+
+ <!-- LinearGradient specific -->
+ <!-- X coordinate of the start point origin of the gradient.
+ Defined in same coordinates as the path itself -->
+ <attr name="startX" format="float" />
+ <!-- Y coordinate of the start point of the gradient within the shape.
+ Defined in same coordinates as the path itself -->
+ <attr name="startY" format="float" />
+ <!-- X coordinate of the end point origin of the gradient.
+ Defined in same coordinates as the path itself -->
+ <attr name="endX" format="float" />
+ <!-- Y coordinate of the end point of the gradient within the shape.
+ Defined in same coordinates as the path itself -->
+ <attr name="endY" format="float" />
+
+ </declare-styleable>
+
+ <!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
+ Colors defined in <item> override the simple color attributes such as
+ "startColor / centerColor / endColor" are ignored -->
+ <declare-styleable name="GradientColorItem">
+ <!-- The offset (or ratio) of this current color item inside the gradient.
+ The value is only meaningful when it is between 0 and 1. -->
+ <attr name="offset" format="float" />
+ <!-- The current color for the offset inside the gradient. -->
+ <attr name="color" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index f92e7f0..7c6f338 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -146,6 +146,9 @@
<!-- The margin on the end of the content view with a picture.-->
<dimen name="notification_content_picture_margin">56dp</dimen>
+ <!-- The margin on the end of the content view with a picture in the compact media.-->
+ <dimen name="notification_content_picture_margin_media">72dp</dimen>
+
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">30dp</dimen>
@@ -169,6 +172,15 @@
<!-- The minimum height of the content if there are at least two lines or a picture-->
<dimen name="notification_min_content_height">41dp</dimen>
+ <!-- The maximum size of the image in the expanded media notification -->
+ <dimen name="media_notification_expanded_image_max_size">94dp</dimen>
+
+ <!-- The maximum size of the image in the expanded media notification -->
+ <dimen name="media_notification_expanded_image_margin_bottom">16dp</dimen>
+
+ <!-- The margin of the content to an image-->
+ <dimen name="notification_content_image_margin_end">8dp</dimen>
+
<!-- Preferred width of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 57132ea..a2ad09b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2691,6 +2691,11 @@
<public type="attr" name="canPerformGestures" />
<public type="attr" name="externalService" />
<public type="attr" name="supportsLocalInteraction" />
+ <public type="attr" name="startX" />
+ <public type="attr" name="startY" />
+ <public type="attr" name="endX" />
+ <public type="attr" name="endY" />
+ <public type="attr" name="offset" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a276854..f415a42 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -559,6 +559,9 @@
<!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
<string name="notification_hidden_text">Contents hidden</string>
+ <!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
+ <string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
@@ -2594,10 +2597,9 @@
<string name="aerr_process"><xliff:g id="process">%1$s</xliff:g> has
stopped</string>
<!-- Text of the alert that is displayed when an application has crashed repeatedly. -->
- <string name="aerr_application_repeated"><xliff:g id="application">%1$s</xliff:g> is repeatedly stopping</string>
+ <string name="aerr_application_repeated"><xliff:g id="application">%1$s</xliff:g> keeps stopping</string>
<!-- Text of the alert that is displayed when a process has crashed repeatedly. -->
- <string name="aerr_process_repeated"><xliff:g id="process">%1$s</xliff:g> is
- repeatedly stopping</string>
+ <string name="aerr_process_repeated"><xliff:g id="process">%1$s</xliff:g> keeps stopping</string>
<!-- Button that restarts a crashed application -->
<string name="aerr_restart">Restart app</string>
<!-- Button that clears cache and restarts a crashed application -->
@@ -2608,17 +2610,21 @@
<string name="aerr_close">Close</string>
<!-- Button that mutes further crashes of the crashed application-->
<string name="aerr_mute">Mute</string>
+ <!-- Button that waits a bit more for an unresponsive app -->
+ <string name="aerr_wait">Wait</string>
+ <!-- Button that closes an unresponsive application -->
+ <string name="aerr_close_app">Close app</string>
<!-- Title of the alert when an application is not responding. -->
<string name="anr_title"></string>
<!-- Text of the alert that is displayed when an application is not responding. -->
- <string name="anr_activity_application"><xliff:g id="application">%2$s</xliff:g> isn\'t responding.\n\nDo you want to close it?</string>
+ <string name="anr_activity_application"><xliff:g id="application">%2$s</xliff:g> isn\'t responding</string>
<!-- Text of the alert that is displayed when an application is not responding. -->
- <string name="anr_activity_process">Activity <xliff:g id="activity">%1$s</xliff:g> isn\'t responding.\n\nDo you want to close it?</string>
+ <string name="anr_activity_process"><xliff:g id="activity">%1$s</xliff:g> isn\'t responding</string>
<!-- Text of the alert that is displayed when an application is not responding. -->
- <string name="anr_application_process"><xliff:g id="application">%1$s</xliff:g> isn\'t responding. Do you want to close it?</string>
+ <string name="anr_application_process"><xliff:g id="application">%1$s</xliff:g> isn\'t responding</string>
<!-- Text of the alert that is displayed when an application is not responding. -->
- <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> isn\'t responding.\n\nDo you want to close it?</string>
+ <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> isn\'t responding</string>
<!-- Button allowing the user to close an application that is not responding. This will kill the application. -->
<string name="force_close">OK</string>
<!-- Button allowing the user to send a bug report for application which has encountered an error. -->
@@ -4000,8 +4006,10 @@
<string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
<!-- Multi-Window strings -->
- <!-- Warning message when a non-resizeble tasks is docked. -->
- <string name="dock_non_resizeble_text">App is not resizeable, scroll it with two fingers.</string>
+ <!-- Warning message when a non-resizeble tasks is docked whose display windows are cropped. -->
+ <string name="dock_cropped_windows_text">App is not resizeable, scroll it with two fingers.</string>
+ <!-- Warning message when we try to dock a non-resizeble tasks and launch it in fullscreen instead. -->
+ <string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
<!-- Notification shown when device owner silently installs a package [CHAR LIMIT=NONE] -->
<string name="package_installed_device_owner">Installed by your administrator</string>
@@ -4149,14 +4157,10 @@
<string name="importance_from_topic">You set the importance of these notifications.</string>
<string name="importance_from_person">This is important because of the people involved.</string>
- <!-- Message to user that app trying to create user is not allowed to due to restrictions. [CHAR LIMIT=none] -->
- <string name="user_creation_cannot_add"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but is currently prohibited.</string>
- <!-- Message to user that app trying to create user is not allowed to due to user limit being reached. [CHAR LIMIT=none] -->
- <string name="user_creation_cannot_add_any_more"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but the user limit has been reached.</string>
<!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
- <string name="user_creation_account_exists"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user, but the account <b><xliff:g id="account" example="foobar">%2$s</xliff:g></b> already exists on this device. Proceed anyway?</string>
+ <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> ?</string>
<!-- Message to user that app is trying to create user for a specified account. [CHAR LIMIT=none] -->
- <string name="user_creation_adding"><b><xliff:g id="app" example="Gmail">%1$s</xliff:g></b> is trying to add a new user for the account <b><xliff:g id="account" example="foobar">%2$s</xliff:g></b>. Proceed?</string>
+ <string name="user_creation_adding">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar">%2$s</xliff:g> (a User with this account already exists) ?</string>
<!-- Locale picker strings -->
@@ -4190,4 +4194,12 @@
<string name="new_sms_notification_title">You have new messages</string>
<!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
<string name="new_sms_notification_content">Open SMS app to view</string>
+
+ <!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_title">Some functions might not be available</string>
+ <!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_message">Touch to continue</string>
+ <!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="user_encrypted_detail">User profile locked</string>
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b660277..f0960c7 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1398,7 +1398,7 @@
</style>
<!-- @hide -->
- <style name="aerr_list_item" parent="Widget.Material.Light.TextView">
+ <style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless">
<item name="minHeight">?attr/listPreferredItemHeightSmall</item>
<item name="textAppearance">?attr/textAppearanceListItemSmall</item>
<item name="textColor">?attr/textColorAlertDialogListItem</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 81705b4..bbfe48a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -610,7 +610,8 @@
<java-symbol type="string" name="display_manager_overlay_display_name" />
<java-symbol type="string" name="display_manager_overlay_display_secure_suffix" />
<java-symbol type="string" name="display_manager_overlay_display_title" />
- <java-symbol type="string" name="dock_non_resizeble_text" />
+ <java-symbol type="string" name="dock_cropped_windows_text" />
+ <java-symbol type="string" name="dock_non_resizeble_failed_to_dock_text" />
<java-symbol type="string" name="double_tap_toast" />
<java-symbol type="string" name="durationDays" />
<java-symbol type="string" name="durationDayHours" />
@@ -937,8 +938,6 @@
<java-symbol type="string" name="time_picker_increment_minute_button" />
<java-symbol type="string" name="time_picker_increment_set_pm_button" />
<java-symbol type="string" name="upload_file" />
- <java-symbol type="string" name="user_creation_cannot_add" />
- <java-symbol type="string" name="user_creation_cannot_add_any_more" />
<java-symbol type="string" name="user_creation_account_exists" />
<java-symbol type="string" name="user_creation_adding" />
<java-symbol type="string" name="user_switched" />
@@ -2390,6 +2389,7 @@
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<!-- EditText suggestion popup. -->
+ <java-symbol type="id" name="suggestionWindowContainer" />
<java-symbol type="id" name="suggestionContainer" />
<java-symbol type="id" name="addToDictionaryButton" />
<java-symbol type="id" name="deleteButton" />
@@ -2401,6 +2401,7 @@
<java-symbol type="string" name="notification_children_count_bracketed" />
<java-symbol type="string" name="notification_hidden_text" />
+ <java-symbol type="string" name="notification_hidden_by_policy_text" />
<java-symbol type="id" name="app_name_text" />
<java-symbol type="id" name="number_of_children" />
<java-symbol type="id" name="header_sub_text" />
@@ -2504,5 +2505,19 @@
<java-symbol type="string" name="new_sms_notification_title" />
<java-symbol type="string" name="new_sms_notification_content" />
+ <java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
+ <java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
+ <java-symbol type="dimen" name="notification_content_image_margin_end" />
+ <java-symbol type="dimen" name="notification_content_picture_margin_media" />
+
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
+
+ <java-symbol type="layout" name="app_anr_dialog" />
+ <java-symbol type="id" name="aerr_wait" />
+
+ <!-- Encryption notification while accounts are locked by credential encryption -->
+ <java-symbol type="string" name="user_encrypted_title" />
+ <java-symbol type="string" name="user_encrypted_message" />
+ <java-symbol type="string" name="user_encrypted_detail" />
+
</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index ddd0ca2..76b5fe1 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -39,15 +39,27 @@
<item name="dsp.video">0.1</item> <!-- ~50mA -->
<item name="camera.flashlight">0.1</item> <!-- Avg. power for camera flash, ~160mA -->
<item name="camera.avg">0.1</item> <!-- Avg. power use of camera in standard usecases, ~550mA -->
+ <item name="gps.on">0.1</item> <!-- ~50mA -->
+
+ <!-- Radio related values. For modems without energy reporting support in firmware, use
+ radio.active, radio.scanning, and radio.on. -->
<item name="radio.active">0.1</item> <!-- ~200mA -->
<item name="radio.scanning">0.1</item> <!-- cellular radio scanning for signal, ~10mA -->
- <item name="gps.on">0.1</item> <!-- ~50mA -->
<!-- Current consumed by the radio at different signal strengths, when paging -->
<array name="radio.on"> <!-- Strength 0 to BINS-1 -->
<value>0.2</value> <!-- ~2mA -->
<value>0.1</value> <!-- ~1mA -->
</array>
+
+ <!-- Radio related values. For modems WITH energy reporting support in firmware, use
+ modem.controller.idle, modem.controller.tx, modem.controller.rx, modem.controller.voltage.
+ -->
+ <item name="modem.controller.idle">0</item>
+ <item name="modem.controller.rx">0</item>
+ <item name="modem.controller.tx">0</item>
+ <item name="modem.controller.voltage">0</item>
+
<!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
number of CPU cores for that cluster.
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 999d47b..d412d7c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -4,9 +4,9 @@
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.
@@ -136,6 +136,12 @@
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
+ <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
+ <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
+ <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
+ <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
+ <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
+
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
<!-- This is a list of all the libraries available for application
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index adb282f..94983b3 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -117,7 +117,10 @@
}
}
- /* package */ long getNativeInstance() {
+ /**
+ * @hide
+ */
+ public long getNativeInstance() {
return native_instance;
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 6526021..1fc1b83 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,6 +17,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.GradientColor;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -27,6 +29,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.PorterDuff.Mode;
+import android.graphics.Shader;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -121,9 +124,9 @@
* <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>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state
- * list. If this property is animated, any value set by the animation will override the original
- * value. No path fill is drawn if this property is not specified.</dd>
+ * <dd>Specifies the color used to fill the path. May be a color, also may be a color state list or
+ * a gradient color for SDK 24+. If this property is animated, any value set by the animation will
+ * override the original value. No path fill is drawn if this property is not specified.</dd>
* <dt><code>android:strokeColor</code></dt>
* <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color
* state list. If this property is animated, any value set by the animation will override the
@@ -1276,8 +1279,9 @@
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private int[] mThemeAttrs;
- ColorStateList mStrokeColors = null;
- ColorStateList mFillColors = null;
+
+ ComplexColor mStrokeColors = null;
+ ComplexColor mFillColors = null;
private long mNativePtr = 0;
public VFullPath() {
@@ -1297,23 +1301,25 @@
public boolean onStateChange(int[] stateSet) {
boolean changed = false;
- if (mStrokeColors != null) {
+ if (mStrokeColors != null && mStrokeColors instanceof ColorStateList) {
final int oldStrokeColor = getStrokeColor();
- final int newStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
+ final int newStrokeColor =
+ ((ColorStateList) mStrokeColors).getColorForState(stateSet, oldStrokeColor);
changed |= oldStrokeColor != newStrokeColor;
if (oldStrokeColor != newStrokeColor) {
nSetStrokeColor(mNativePtr, newStrokeColor);
}
}
- if (mFillColors != null) {
+ if (mFillColors != null && mFillColors instanceof ColorStateList) {
final int oldFillColor = getFillColor();
- final int newFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
+ final int newFillColor = ((ColorStateList) mFillColors).getColorForState(stateSet, oldFillColor);
changed |= oldFillColor != newFillColor;
if (oldFillColor != newFillColor) {
nSetFillColor(mNativePtr, newFillColor);
}
}
+
return changed;
}
@@ -1372,7 +1378,8 @@
int strokeLineCap = properties.getInt(STROKE_LINE_CAP_INDEX * 4);
int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
-
+ Shader fillGradient = null;
+ Shader strokeGradient = null;
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1391,23 +1398,43 @@
nSetPathString(mNativePtr, pathString, pathString.length());
}
- final ColorStateList fillColors = a.getColorStateList(
+ final ComplexColor fillColors = a.getComplexColor(
R.styleable.VectorDrawablePath_fillColor);
if (fillColors != null) {
- // If the color state list isn't stateful, discard the state
- // list and keep the default (e.g. the only) color.
- mFillColors = fillColors.isStateful() ? fillColors : null;
+ // If the colors is a gradient color, or the color state list is stateful, keep the
+ // colors information. Otherwise, discard the colors and keep the default color.
+ if (fillColors instanceof GradientColor) {
+ mFillColors = fillColors;
+ fillGradient = ((GradientColor) fillColors).getShader();
+ } else if (fillColors.isStateful()) {
+ mFillColors = fillColors;
+ } else {
+ mFillColors = null;
+ }
fillColor = fillColors.getDefaultColor();
}
- final ColorStateList strokeColors = a.getColorStateList(
+ final ComplexColor strokeColors = a.getComplexColor(
R.styleable.VectorDrawablePath_strokeColor);
if (strokeColors != null) {
- // If the color state list isn't stateful, discard the state
- // list and keep the default (e.g. the only) color.
- mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
+ // If the colors is a gradient color, or the color state list is stateful, keep the
+ // colors information. Otherwise, discard the colors and keep the default color.
+ if (strokeColors instanceof GradientColor) {
+ mStrokeColors = strokeColors;
+ strokeGradient = ((GradientColor) strokeColors).getShader();
+ } else if (strokeColors.isStateful()) {
+ mStrokeColors = strokeColors;
+ } else {
+ mStrokeColors = null;
+ }
strokeColor = strokeColors.getDefaultColor();
}
+ // Update the gradient info, even if the gradiet is null.
+ nUpdateFullPathFillGradient(mNativePtr,
+ fillGradient != null ? fillGradient.getNativeInstance() : 0);
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ strokeGradient != null ? strokeGradient.getNativeInstance() : 0);
+
fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
strokeLineCap = a.getInt(
@@ -1434,18 +1461,44 @@
@Override
public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ if (mThemeAttrs != null) {
+ return true;
+ }
+ boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ if (fillCanApplyTheme || strokeCanApplyTheme) {
+ return true;
+ }
+ return false;
+
}
@Override
public void applyTheme(Theme t) {
- if (mThemeAttrs == null) {
- return;
+ if (mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+ updateStateFromTypedArray(a);
+ a.recycle();
}
- final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
- updateStateFromTypedArray(a);
- a.recycle();
+ boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ if (fillCanApplyTheme) {
+ mFillColors = mFillColors.obtainForTheme(t);
+ nUpdateFullPathFillGradient(mNativePtr,
+ ((GradientColor)mFillColors).getShader().getNativeInstance());
+ }
+
+ if (strokeCanApplyTheme) {
+ mStrokeColors = mStrokeColors.obtainForTheme(t);
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+ }
+ }
+
+ private boolean canGradientApplyTheme(ComplexColor complexColor) {
+ return complexColor != null && complexColor.canApplyTheme()
+ && complexColor instanceof GradientColor;
}
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@@ -1560,6 +1613,8 @@
int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
int strokeLineJoin);
+ private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+ private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
private static native long nCreateClipPath();
private static native long nCreateClipPath(long clipPathPtr);
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 5736c70..35c8f6b 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -43,7 +43,7 @@
mRenderTarget.offscreenBuffer = offscreenBuffer;
// create and bind framebuffer
- mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
+ mRenderTarget.frameBufferId = mRenderState.createFramebuffer();
mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
// attach the texture to the FBO
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 3123e8e..e04b9a2 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -189,7 +189,7 @@
LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
Caches& caches = Caches::getInstance();
- GLuint fbo = renderState.genFramebuffer();
+ GLuint fbo = renderState.createFramebuffer();
if (!fbo) {
ALOGW("Could not obtain an FBO");
return nullptr;
@@ -357,7 +357,7 @@
&& bitmap->width() <= caches.maxTextureSize
&& bitmap->height() <= caches.maxTextureSize) {
- GLuint fbo = renderState.getFramebuffer();
+ GLuint fbo = renderState.createFramebuffer();
if (!fbo) {
ALOGW("Could not obtain an FBO");
return false;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6c2e244..587be92 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -674,7 +674,7 @@
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
layer->clipRect.set(clip);
- layer->setFbo(mRenderState.genFramebuffer());
+ layer->setFbo(mRenderState.createFramebuffer());
writableSnapshot()->region = &writableSnapshot()->layer->region;
writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 1d31c9e..1cf15ac 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -18,6 +18,7 @@
#include "PathParser.h"
#include "SkImageInfo.h"
+#include "SkShader.h"
#include <utils/Log.h>
#include "utils/Macros.h"
#include "utils/VectorDrawableUtils.h"
@@ -49,7 +50,7 @@
float minScale = fmin(scaleX, scaleY);
float strokeScale = minScale * matrixScale;
- drawPath(outCanvas, renderPath, strokeScale);
+ drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
}
void Path::setPathData(const Data& data) {
@@ -148,6 +149,9 @@
mStrokeMiterLimit = path.mStrokeMiterLimit;
mStrokeLineCap = path.mStrokeLineCap;
mStrokeLineJoin = path.mStrokeLineJoin;
+
+ SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
+ SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
}
const SkPath& FullPath::getUpdatedPath() {
@@ -186,22 +190,43 @@
return SkColorSetA(color, alphaBytes * alpha);
}
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale){
- // Draw path's fill, if fill color isn't transparent.
- if (mFillColor != SK_ColorTRANSPARENT) {
+void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
+ const SkMatrix& matrix){
+ // Draw path's fill, if fill color or gradient is valid
+ bool needsFill = false;
+ if (mFillGradient != nullptr) {
+ mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+ SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
+ mPaint.setShader(newShader);
+ needsFill = true;
+ } else if (mFillColor != SK_ColorTRANSPARENT) {
+ mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+ needsFill = true;
+ }
+
+ if (needsFill) {
mPaint.setStyle(SkPaint::Style::kFill_Style);
mPaint.setAntiAlias(true);
- mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
outCanvas->drawPath(renderPath, mPaint);
}
- // Draw path's stroke, if stroke color isn't transparent
- if (mStrokeColor != SK_ColorTRANSPARENT) {
+
+ // Draw path's stroke, if stroke color or gradient is valid
+ bool needsStroke = false;
+ if (mStrokeGradient != nullptr) {
+ mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+ SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
+ mPaint.setShader(newShader);
+ needsStroke = true;
+ } else if (mStrokeColor != SK_ColorTRANSPARENT) {
+ mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+ needsStroke = true;
+ }
+ if (needsStroke) {
mPaint.setStyle(SkPaint::Style::kStroke_Style);
mPaint.setAntiAlias(true);
mPaint.setStrokeJoin(mStrokeLineJoin);
mPaint.setStrokeCap(mStrokeLineCap);
mPaint.setStrokeMiter(mStrokeMiterLimit);
- mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
outCanvas->drawPath(renderPath, mPaint);
}
@@ -288,7 +313,7 @@
}
void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale){
+ float strokeScale, const SkMatrix& matrix){
outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 5ae5f6a..09bdce5 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -26,6 +26,7 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
+#include <SkShader.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -95,7 +96,7 @@
protected:
virtual const SkPath& getUpdatedPath();
virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
- float strokeScale) = 0;
+ float strokeScale, const SkMatrix& matrix) = 0;
Data mData;
SkPath mSkPath;
bool mSkPathDirty = true;
@@ -108,6 +109,11 @@
FullPath() : Path() {}
FullPath(const Data& nodes) : Path(nodes) {}
+ ~FullPath() {
+ SkSafeUnref(mFillGradient);
+ SkSafeUnref(mStrokeGradient);
+ }
+
void updateProperties(float strokeWidth, SkColor strokeColor,
float strokeAlpha, SkColor fillColor, float fillAlpha,
float trimPathStart, float trimPathEnd, float trimPathOffset,
@@ -162,10 +168,18 @@
}
bool getProperties(int8_t* outProperties, int length);
+ void setFillGradient(SkShader* fillGradient) {
+ SkRefCnt_SafeAssign(mFillGradient, fillGradient);
+ };
+ void setStrokeGradient(SkShader* strokeGradient) {
+ SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
+ };
+
+
protected:
const SkPath& getUpdatedPath() override;
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale) override;
+ float strokeScale, const SkMatrix& matrix) override;
private:
// Applies trimming to the specified path.
@@ -174,6 +188,8 @@
SkColor mStrokeColor = SK_ColorTRANSPARENT;
float mStrokeAlpha = 1;
SkColor mFillColor = SK_ColorTRANSPARENT;
+ SkShader* mStrokeGradient = nullptr;
+ SkShader* mFillGradient = nullptr;
float mFillAlpha = 1;
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
@@ -195,7 +211,7 @@
protected:
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale) override;
+ float strokeScale, const SkMatrix& matrix) override;
};
class ANDROID_API Group: public Node {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 81363d9..e535f2f 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -144,7 +144,7 @@
}
}
-GLuint RenderState::genFramebuffer() {
+GLuint RenderState::createFramebuffer() {
GLuint ret;
glGenFramebuffers(1, &ret);
return ret;
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index e5d3e79..731d9bb 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -64,7 +64,7 @@
void bindFramebuffer(GLuint fbo);
GLuint getFramebuffer() { return mFramebuffer; }
- GLuint genFramebuffer();
+ GLuint createFramebuffer();
void deleteFramebuffer(GLuint fbo);
void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
diff --git a/location/java/android/location/GnssNmeaListener.java b/location/java/android/location/GnssNmeaListener.java
new file mode 100644
index 0000000..6c9b08a
--- /dev/null
+++ b/location/java/android/location/GnssNmeaListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+/**
+* Used for receiving NMEA sentences from the GNSS.
+* NMEA 0183 is a standard for communicating with marine electronic devices
+* and is a common method for receiving data from a GNSS, typically over a serial port.
+* See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+* You can implement this interface and call {@link LocationManager#addNmeaListener}
+* to receive NMEA data from the GNSS engine.
+*/
+public interface GnssNmeaListener {
+ /** Called when an NMEA message is received. */
+ void onNmeaReceived(long timestamp, String nmea);
+}
\ No newline at end of file
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
new file mode 100644
index 0000000..77e8a5b
--- /dev/null
+++ b/location/java/android/location/GnssStatus.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+/**
+ * This class represents the current state of the GNSS engine.
+ * This class is used in conjunction with the {@link GnssStatusCallback}.
+ */
+public final class GnssStatus {
+ /** Unknown constellation type. */
+ public static final int CONSTELLATION_UNKNOWN = 0;
+ /** Constellation type constant for GPS. */
+ public static final int CONSTELLATION_GPS = 1;
+ /** Constellation type constant for SBAS. */
+ public static final int CONSTELLATION_SBAS = 2;
+ /** Constellation type constant for Glonass. */
+ public static final int CONSTELLATION_GLONASS = 3;
+ /** Constellation type constant for QZSS. */
+ public static final int CONSTELLATION_QZSS = 4;
+ /** Constellation type constant for Beidou. */
+ public static final int CONSTELLATION_BEIDOU = 5;
+ /** Constellation type constant for Galileo. */
+ public static final int CONSTELLATION_GALILEO = 6;
+
+ // these must match the definitions in gps.h
+ /** @hide */
+ public static final int GNSS_SV_FLAGS_NONE = 0;
+ /** @hide */
+ public static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0);
+ /** @hide */
+ public static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
+ /** @hide */
+ public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
+
+ /** @hide */
+ public static final int PRN_SHIFT_WIDTH = 3;
+
+ /* These package private values are modified by the LocationManager class */
+ /* package */ int[] mPrnWithFlags;
+ /* package */ float[] mSnrs;
+ /* package */ float[] mElevations;
+ /* package */ float[] mAzimuths;
+ /* package */ int[] mConstellationTypes;
+ /* package */ int mSvCount;
+
+ GnssStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations, float[] azimuths,
+ int[] constellationTypes) {
+ mSvCount = svCount;
+ mPrnWithFlags = prnWithFlags;
+ mSnrs = snrs;
+ mElevations = elevations;
+ mAzimuths = azimuths;
+ mConstellationTypes = constellationTypes;
+ }
+
+ /**
+ * Gets the total number of satellites in satellite list.
+ */
+ public int getNumSatellites() {
+ return mSvCount;
+ }
+
+ /**
+ * Retrieves the constellation type of the satellite at the specified position.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public int getConstellationType(int satIndex) {
+ return mConstellationTypes[satIndex];
+ }
+
+ /**
+ * Retrieves the pseudo-random number of the satellite at the specified position.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public int getPrn(int satIndex) {
+ return mPrnWithFlags[satIndex] >> PRN_SHIFT_WIDTH;
+ }
+
+ /**
+ * Retrieves the signal-noise ration of the satellite at the specified position.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public float getSnr(int satIndex) {
+ return mSnrs[satIndex];
+ }
+
+ /**
+ * Retrieves the elevation of the satellite at the specified position.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public float getElevation(int satIndex) {
+ return 0f;
+ }
+
+ /**
+ * Retrieves the azimuth the satellite at the specified position.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public float getAzimuth(int satIndex) {
+ return mAzimuths[satIndex];
+ }
+
+ /**
+ * Detects whether the satellite at the specified position has ephemeris data.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public boolean hasEphemeris(int satIndex) {
+ return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ }
+
+ /**
+ * Detects whether the satellite at the specified position has almanac data.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public boolean hasAlmanac(int satIndex) {
+ return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ }
+
+ /**
+ * Detects whether the satellite at the specified position is used in fix.
+ * @param satIndex the index of the satellite in the list.
+ */
+ public boolean usedInFix(int satIndex) {
+ return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+ }
+}
diff --git a/location/java/android/location/GnssStatusCallback.java b/location/java/android/location/GnssStatusCallback.java
new file mode 100644
index 0000000..b86171b
--- /dev/null
+++ b/location/java/android/location/GnssStatusCallback.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+/**
+ * Used for receiving notifications when GNSS events happen.
+ */
+public abstract class GnssStatusCallback {
+ /**
+ * Called when GNSS system has started.
+ */
+ public void onStarted() {}
+
+ /**
+ * Called when GNSS system has stopped.
+ */
+ public void onStopped() {}
+
+ /**
+ * Called when the GNSS system has received its first fix since starting.
+ * @param ttff the time from start to first fix.
+ */
+ public void onFirstFix(int ttff) {}
+
+ /**
+ * Called periodically to report GNSS satellite status.
+ * @param status the current status of all satellites.
+ */
+ public void onSatelliteStatusChanged(GnssStatus status) {}
+}
\ No newline at end of file
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 4135a1c..719e56f 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -16,36 +16,41 @@
package android.location;
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A class containing a GPS clock timestamp.
* It represents a measurement of the GPS receiver's clock.
- *
- * @hide
*/
-@SystemApi
-public class GpsClock implements Parcelable {
+public final class GpsClock implements Parcelable {
// The following enumerations must be in sync with the values declared in gps.h
+ /** The type of the GPS Clock. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME})
+ public @interface GpsClockType {}
+
/**
* The type of the time stored is not available or it is unknown.
*/
- public static final byte TYPE_UNKNOWN = 0;
+ public static final byte CLOCK_TYPE_UNKNOWN = 0;
/**
* The source of the time value reported by this class is the 'Local Hardware Clock'.
*/
- public static final byte TYPE_LOCAL_HW_TIME = 1;
+ public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1;
/**
* The source of the time value reported by this class is the 'GPS time' derived from
* satellites (epoch = Jan 6, 1980).
*/
- public static final byte TYPE_GPS_TIME = 2;
+ public static final byte CLOCK_TYPE_GPS_TIME = 2;
private static final short HAS_NO_FLAGS = 0;
private static final short HAS_LEAP_SECOND = (1<<0);
@@ -68,6 +73,7 @@
private double mBiasUncertaintyInNs;
private double mDriftInNsPerSec;
private double mDriftUncertaintyInNsPerSec;
+ private long mTimeOfLastHwClockDiscontinuityInNs;
GpsClock() {
initialize();
@@ -87,6 +93,7 @@
mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
mDriftInNsPerSec = clock.mDriftInNsPerSec;
mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+ mTimeOfLastHwClockDiscontinuityInNs = clock.mTimeOfLastHwClockDiscontinuityInNs;
}
/**
@@ -99,6 +106,7 @@
/**
* Gets the type of time reported by {@link #getTimeInNs()}.
*/
+ @GpsClockType
public byte getType() {
return mType;
}
@@ -106,7 +114,7 @@
/**
* Sets the type of time reported.
*/
- public void setType(byte value) {
+ public void setType(@GpsClockType byte value) {
mType = value;
}
@@ -116,11 +124,11 @@
*/
private String getTypeString() {
switch (mType) {
- case TYPE_UNKNOWN:
+ case CLOCK_TYPE_UNKNOWN:
return "Unknown";
- case TYPE_GPS_TIME:
+ case CLOCK_TYPE_GPS_TIME:
return "GpsTime";
- case TYPE_LOCAL_HW_TIME:
+ case CLOCK_TYPE_LOCAL_HW_TIME:
return "LocalHwClock";
default:
return "<Invalid:" + mType + ">";
@@ -163,8 +171,8 @@
/**
* Gets the GPS receiver internal clock value in nanoseconds.
- * This can be either the 'local hardware clock' value ({@link #TYPE_LOCAL_HW_TIME}), or the
- * current GPS time derived inside GPS receiver ({@link #TYPE_GPS_TIME}).
+ * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the
+ * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}).
* {@link #getType()} defines the time reported.
*
* For 'local hardware clock' this value is expected to be monotonically increasing during the
@@ -223,7 +231,7 @@
}
/**
- * Returns true if {@link @getFullBiasInNs()} is available, false otherwise.
+ * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
*/
public boolean hasFullBiasInNs() {
return isFlagSet(HAS_FULL_BIAS);
@@ -233,7 +241,7 @@
* Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
* the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
*
- * This value is available if {@link #TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
+ * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
* the clock for GPS time.
* {@link #getBiasUncertaintyInNs()} should be used for quality check.
*
@@ -387,6 +395,20 @@
}
/**
+ * Gets time of last hardware clock discontinuity.
+ */
+ public long getTimeOfLastHwClockDiscontinuityInNs() {
+ return mTimeOfLastHwClockDiscontinuityInNs;
+ }
+
+ /**
+ * Sets time of last hardware clock discontinuity.
+ */
+ public void setTimeOfLastHwClockDiscontinuityInNs(long timeOfLastHwClockDiscontinuityInNs) {
+ mTimeOfLastHwClockDiscontinuityInNs = timeOfLastHwClockDiscontinuityInNs;
+ }
+
+ /**
* Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*/
public void resetDriftUncertaintyInNsPerSec() {
@@ -409,6 +431,7 @@
gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
gpsClock.mDriftInNsPerSec = parcel.readDouble();
gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+ gpsClock.mTimeOfLastHwClockDiscontinuityInNs = parcel.readLong();
return gpsClock;
}
@@ -430,6 +453,7 @@
parcel.writeDouble(mBiasUncertaintyInNs);
parcel.writeDouble(mDriftInNsPerSec);
parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+ parcel.writeLong(mTimeOfLastHwClockDiscontinuityInNs);
}
@Override
@@ -473,13 +497,17 @@
"DriftUncertaintyInNsPerSec",
hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
+ builder.append(String.format(format, "TimeOfLastHwClockDiscontinuityInNs",
+ getType() == CLOCK_TYPE_LOCAL_HW_TIME
+ ? mTimeOfLastHwClockDiscontinuityInNs : null));
+
return builder.toString();
}
private void initialize() {
mFlags = HAS_NO_FLAGS;
resetLeapSecond();
- setType(TYPE_UNKNOWN);
+ setType(CLOCK_TYPE_UNKNOWN);
setTimeInNs(Long.MIN_VALUE);
resetTimeUncertaintyInNs();
resetFullBiasInNs();
@@ -487,6 +515,7 @@
resetBiasUncertaintyInNs();
resetDriftInNsPerSec();
resetDriftUncertaintyInNsPerSec();
+ setTimeOfLastHwClockDiscontinuityInNs(Long.MIN_VALUE);
}
private void setFlag(short flag) {
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index f13a440..366ad61 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -16,17 +16,17 @@
package android.location;
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A class representing a GPS satellite measurement, containing raw and computed information.
- *
- * @hide
*/
-@SystemApi
-public class GpsMeasurement implements Parcelable {
+public final class GpsMeasurement implements Parcelable {
private int mFlags;
private byte mPrn;
private double mTimeOffsetInNs;
@@ -59,6 +59,8 @@
private double mAzimuthInDeg;
private double mAzimuthUncertaintyInDeg;
private boolean mUsedInFix;
+ private double mPseudorangeRateCarrierInMetersPerSec;
+ private double mPseudorangeRateCarrierUncertaintyInMetersPerSec;
// The following enumerations must be in sync with the values declared in gps.h
@@ -83,6 +85,11 @@
private static final int HAS_USED_IN_FIX = (1<<17);
private static final int GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
+ /** The status of 'loss of lock'. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({LOSS_OF_LOCK_UNKNOWN, LOSS_OF_LOCK_OK, LOSS_OF_LOCK_CYCLE_SLIP})
+ public @interface LossOfLockStatus {}
+
/**
* The indicator is not available or it is unknown.
*/
@@ -98,6 +105,12 @@
*/
public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
+ /** The status of multipath. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED,
+ MULTIPATH_INDICATOR_NOT_USED})
+ public @interface MultipathIndicator {}
+
/**
* The indicator is not available or it is unknown.
*/
@@ -218,6 +231,10 @@
mAzimuthInDeg = measurement.mAzimuthInDeg;
mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
mUsedInFix = measurement.mUsedInFix;
+ mPseudorangeRateCarrierInMetersPerSec =
+ measurement.mPseudorangeRateCarrierInMetersPerSec;
+ mPseudorangeRateCarrierUncertaintyInMetersPerSec =
+ measurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec;
}
/**
@@ -776,6 +793,7 @@
/**
* Gets a value indicating the 'loss of lock' state of the event.
*/
+ @LossOfLockStatus
public byte getLossOfLock() {
return mLossOfLock;
}
@@ -783,7 +801,7 @@
/**
* Sets the 'loss of lock' status.
*/
- public void setLossOfLock(byte value) {
+ public void setLossOfLock(@LossOfLockStatus byte value) {
mLossOfLock = value;
}
@@ -941,6 +959,7 @@
/**
* Gets a value indicating the 'multipath' state of the event.
*/
+ @MultipathIndicator
public byte getMultipathIndicator() {
return mMultipathIndicator;
}
@@ -948,7 +967,7 @@
/**
* Sets the 'multi-path' indicator.
*/
- public void setMultipathIndicator(byte value) {
+ public void setMultipathIndicator(@MultipathIndicator byte value) {
mMultipathIndicator = value;
}
@@ -1157,6 +1176,34 @@
mUsedInFix = value;
}
+ /**
+ * Gets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+ */
+ public double getPseudorangeRateCarrierInMetersPerSec() {
+ return mPseudorangeRateCarrierInMetersPerSec;
+ }
+
+ /**
+ * Sets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+ */
+ public void setPseudorangeRateCarrierInMetersPerSec(double value) {
+ mPseudorangeRateCarrierInMetersPerSec = value;
+ }
+
+ /**
+ * Gets 1-Sigma uncertainty of the pseudorange rate carrier.
+ */
+ public double getPseudorangeRateCarrierUncertaintyInMetersPerSec() {
+ return mPseudorangeRateCarrierUncertaintyInMetersPerSec;
+ }
+
+ /**
+ * Sets 1-Sigma uncertainty of the pseudorange rate carrier.
+ */
+ public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double value) {
+ mPseudorangeRateCarrierUncertaintyInMetersPerSec = value;
+ }
+
public static final Creator<GpsMeasurement> CREATOR = new Creator<GpsMeasurement>() {
@Override
public GpsMeasurement createFromParcel(Parcel parcel) {
@@ -1194,6 +1241,8 @@
gpsMeasurement.mAzimuthInDeg = parcel.readDouble();
gpsMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
gpsMeasurement.mUsedInFix = parcel.readInt() != 0;
+ gpsMeasurement.mPseudorangeRateCarrierInMetersPerSec = parcel.readDouble();
+ gpsMeasurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec = parcel.readDouble();
return gpsMeasurement;
}
@@ -1237,6 +1286,8 @@
parcel.writeDouble(mAzimuthInDeg);
parcel.writeDouble(mAzimuthUncertaintyInDeg);
parcel.writeInt(mUsedInFix ? 1 : 0);
+ parcel.writeDouble(mPseudorangeRateCarrierInMetersPerSec);
+ parcel.writeDouble(mPseudorangeRateCarrierUncertaintyInMetersPerSec);
}
@Override
@@ -1361,6 +1412,11 @@
builder.append(String.format(format, "UsedInFix", mUsedInFix));
+ builder.append(String.format(format, "PseudorangeRateCarrierInMetersPerSec",
+ mPseudorangeRateCarrierInMetersPerSec));
+ builder.append(String.format(format, "PseudorangeRateCarrierUncertaintyInMetersPerSec",
+ mPseudorangeRateCarrierUncertaintyInMetersPerSec));
+
return builder.toString();
}
@@ -1397,6 +1453,8 @@
resetAzimuthInDeg();
resetAzimuthUncertaintyInDeg();
setUsedInFix(false);
+ setPseudorangeRateCarrierInMetersPerSec(Double.MIN_VALUE);
+ setPseudorangeRateCarrierUncertaintyInMetersPerSec(Double.MIN_VALUE);
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementCallbackTransport.java
similarity index 68%
rename from location/java/android/location/GpsMeasurementListenerTransport.java
rename to location/java/android/location/GpsMeasurementCallbackTransport.java
index 610da96..02d9026 100644
--- a/location/java/android/location/GpsMeasurementListenerTransport.java
+++ b/location/java/android/location/GpsMeasurementCallbackTransport.java
@@ -20,17 +20,17 @@
import android.os.RemoteException;
/**
- * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
+ * A handler class to manage transport callbacks for {@link GpsMeasurementsEvent.Callback}.
*
* @hide
*/
-class GpsMeasurementListenerTransport
- extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
+class GpsMeasurementCallbackTransport
+ extends LocalListenerHelper<GpsMeasurementsEvent.Callback> {
private final ILocationManager mLocationManager;
private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
- public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
+ public GpsMeasurementCallbackTransport(Context context, ILocationManager locationManager) {
super(context, "GpsMeasurementListenerTransport");
mLocationManager = locationManager;
}
@@ -50,11 +50,11 @@
private class ListenerTransport extends IGpsMeasurementsListener.Stub {
@Override
public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
- ListenerOperation<GpsMeasurementsEvent.Listener> operation =
- new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+ ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+ new ListenerOperation<GpsMeasurementsEvent.Callback>() {
@Override
- public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
- listener.onGpsMeasurementsReceived(event);
+ public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+ callback.onGpsMeasurementsReceived(event);
}
};
foreach(operation);
@@ -62,11 +62,11 @@
@Override
public void onStatusChanged(final int status) {
- ListenerOperation<GpsMeasurementsEvent.Listener> operation =
- new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+ ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+ new ListenerOperation<GpsMeasurementsEvent.Callback>() {
@Override
- public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
- listener.onStatusChanged(status);
+ public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+ callback.onStatusChanged(status);
}
};
foreach(operation);
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
index 1366873..ef9edeb 100644
--- a/location/java/android/location/GpsMeasurementsEvent.java
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -16,11 +16,13 @@
package android.location;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Collection;
@@ -28,12 +30,13 @@
/**
* A class implementing a container for data associated with a measurement event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
*/
-@SystemApi
-public class GpsMeasurementsEvent implements Parcelable {
+public final class GpsMeasurementsEvent implements Parcelable {
+ /** The status of GPS measurements event. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+ public @interface GpsMeasurementsStatus {}
/**
* The system does not support tracking of GPS Measurements. This status will not change in the
@@ -58,22 +61,20 @@
/**
* Used for receiving GPS satellite measurements from the GPS engine.
* Each measurement contains raw and computed data identifying a satellite.
- * You can implement this interface and call {@link LocationManager#addGpsMeasurementListener}.
- *
- * @hide
+ * You can implement this interface and call
+ * {@link LocationManager#registerGpsMeasurementCallback}.
*/
- @SystemApi
- public interface Listener {
+ public static abstract class Callback {
/**
* Returns the latest collected GPS Measurements.
*/
- void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
+ public void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs) {}
/**
* Returns the latest status of the GPS Measurements sub-system.
*/
- void onStatusChanged(int status);
+ public void onStatusChanged(@GpsMeasurementsStatus int status) {}
}
public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 5c3c710..d799572 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -16,49 +16,54 @@
package android.location;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.security.InvalidParameterException;
/**
* A class containing a GPS satellite Navigation Message.
- *
- * @hide
*/
-@SystemApi
-public class GpsNavigationMessage implements Parcelable {
+public final class GpsNavigationMessage implements Parcelable {
private static final byte[] EMPTY_ARRAY = new byte[0];
+ /** The type of the GPS Clock. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_L1CA, MESSAGE_TYPE_L2CNAV, MESSAGE_TYPE_L5CNAV,
+ MESSAGE_TYPE_CNAV2})
+ public @interface GpsNavigationMessageType {}
+
// The following enumerations must be in sync with the values declared in gps.h
/**
* The type of the navigation message is not available or unknown.
*/
- public static final byte TYPE_UNKNOWN = 0;
+ public static final byte MESSAGE_TYPE_UNKNOWN = 0;
/**
* The Navigation Message is of type L1 C/A.
*/
- public static final byte TYPE_L1CA = 1;
+ public static final byte MESSAGE_TYPE_L1CA = 1;
/**
* The Navigation Message is of type L1-CNAV.
*/
- public static final byte TYPE_L2CNAV = 2;
+ public static final byte MESSAGE_TYPE_L2CNAV = 2;
/**
* The Navigation Message is of type L5-CNAV.
*/
- public static final byte TYPE_L5CNAV = 3;
+ public static final byte MESSAGE_TYPE_L5CNAV = 3;
/**
* The Navigation Message is of type CNAV-2.
*/
- public static final byte TYPE_CNAV2 = 4;
+ public static final byte MESSAGE_TYPE_CNAV2 = 4;
/**
* The Navigation Message Status is 'unknown'.
@@ -111,6 +116,7 @@
/**
* Gets the type of the navigation message contained in the object.
*/
+ @GpsNavigationMessageType
public byte getType() {
return mType;
}
@@ -118,7 +124,7 @@
/**
* Sets the type of the navigation message.
*/
- public void setType(byte value) {
+ public void setType(@GpsNavigationMessageType byte value) {
mType = value;
}
@@ -128,15 +134,15 @@
*/
private String getTypeString() {
switch (mType) {
- case TYPE_UNKNOWN:
+ case MESSAGE_TYPE_UNKNOWN:
return "Unknown";
- case TYPE_L1CA:
+ case MESSAGE_TYPE_L1CA:
return "L1 C/A";
- case TYPE_L2CNAV:
+ case MESSAGE_TYPE_L2CNAV:
return "L2-CNAV";
- case TYPE_L5CNAV:
+ case MESSAGE_TYPE_L5CNAV:
return "L5-CNAV";
- case TYPE_CNAV2:
+ case MESSAGE_TYPE_CNAV2:
return "CNAV-2";
default:
return "<Invalid:" + mType + ">";
@@ -314,7 +320,7 @@
}
private void initialize() {
- mType = TYPE_UNKNOWN;
+ mType = MESSAGE_TYPE_UNKNOWN;
mPrn = 0;
mMessageId = -1;
mSubmessageId = -1;
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
similarity index 73%
rename from location/java/android/location/GpsNavigationMessageListenerTransport.java
rename to location/java/android/location/GpsNavigationMessageCallbackTransport.java
index f6ba407..155d96d 100644
--- a/location/java/android/location/GpsNavigationMessageListenerTransport.java
+++ b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
@@ -20,20 +20,20 @@
import android.os.RemoteException;
/**
- * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
+ * A handler class to manage transport callback for {@link GpsNavigationMessageEvent.Callback}.
*
* @hide
*/
-class GpsNavigationMessageListenerTransport
- extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
+class GpsNavigationMessageCallbackTransport
+ extends LocalListenerHelper<GpsNavigationMessageEvent.Callback> {
private final ILocationManager mLocationManager;
private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
- public GpsNavigationMessageListenerTransport(
+ public GpsNavigationMessageCallbackTransport(
Context context,
ILocationManager locationManager) {
- super(context, "GpsNavigationMessageListenerTransport");
+ super(context, "GpsNavigationMessageCallbackTransport");
mLocationManager = locationManager;
}
@@ -52,12 +52,12 @@
private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
@Override
public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
- ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
- new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+ ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+ new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
@Override
- public void execute(GpsNavigationMessageEvent.Listener listener)
+ public void execute(GpsNavigationMessageEvent.Callback callback)
throws RemoteException {
- listener.onGpsNavigationMessageReceived(event);
+ callback.onGpsNavigationMessageReceived(event);
}
};
foreach(operation);
@@ -65,12 +65,12 @@
@Override
public void onStatusChanged(final int status) {
- ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
- new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+ ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+ new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
@Override
- public void execute(GpsNavigationMessageEvent.Listener listener)
+ public void execute(GpsNavigationMessageEvent.Callback callback)
throws RemoteException {
- listener.onStatusChanged(status);
+ callback.onStatusChanged(status);
}
};
foreach(operation);
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
index bd6921c..b16a485 100644
--- a/location/java/android/location/GpsNavigationMessageEvent.java
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -16,60 +16,60 @@
package android.location;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.security.InvalidParameterException;
/**
* A class implementing a container for data associated with a navigation message event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
*/
-@SystemApi
-public class GpsNavigationMessageEvent implements Parcelable {
+public final class GpsNavigationMessageEvent implements Parcelable {
+ /** The status of GPS measurements event. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+ public @interface GpsNavigationMessageStatus {}
/**
* The system does not support tracking of GPS Navigation Messages. This status will not change
* in the future.
*/
- public static int STATUS_NOT_SUPPORTED = 0;
+ public static final int STATUS_NOT_SUPPORTED = 0;
/**
* GPS Navigation Messages are successfully being tracked, it will receive updates once they are
* available.
*/
- public static int STATUS_READY = 1;
+ public static final int STATUS_READY = 1;
/**
* GPS provider or Location is disabled, updated will not be received until they are enabled.
*/
- public static int STATUS_GPS_LOCATION_DISABLED = 2;
+ public static final int STATUS_GPS_LOCATION_DISABLED = 2;
private final GpsNavigationMessage mNavigationMessage;
/**
* Used for receiving GPS satellite Navigation Messages from the GPS engine.
* You can implement this interface and call
- * {@link LocationManager#addGpsNavigationMessageListener}.
- *
- * @hide
+ * {@link LocationManager#registerGpsNavigationMessageCallback}.
*/
- @SystemApi
- public interface Listener {
+ public static abstract class Callback {
/**
* Returns the latest collected GPS Navigation Message.
*/
- void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+ public void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event) {}
/**
* Returns the latest status of the GPS Navigation Messages sub-system.
*/
- void onStatusChanged(int status);
+ public void onStatusChanged(@GpsNavigationMessageStatus int status) {}
}
public GpsNavigationMessageEvent(GpsNavigationMessage message) {
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 323f326..8d2f781 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -34,17 +34,15 @@
private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
private final class SatelliteIterator implements Iterator<GpsSatellite> {
-
- private final SparseArray<GpsSatellite> mSatellites;
private final int mSatellitesCount;
private int mIndex = 0;
- SatelliteIterator(SparseArray<GpsSatellite> satellites) {
- mSatellites = satellites;
- mSatellitesCount = satellites.size();
+ SatelliteIterator() {
+ mSatellitesCount = mSatellites.size();
}
+ @Override
public boolean hasNext() {
for (; mIndex < mSatellitesCount; ++mIndex) {
GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -55,6 +53,7 @@
return false;
}
+ @Override
public GpsSatellite next() {
while (mIndex < mSatellitesCount) {
GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -66,14 +65,16 @@
throw new NoSuchElementException();
}
+ @Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
+ @Override
public Iterator<GpsSatellite> iterator() {
- return new SatelliteIterator(mSatellites);
+ return new SatelliteIterator();
}
};
@@ -137,18 +138,15 @@
// For API-compat a public ctor() is not available
GpsStatus() {}
- /**
- * Used internally within {@link LocationManager} to copy GPS status
- * data from the Location Manager Service to its cached GpsStatus instance.
- * Is synchronized to ensure that GPS status updates are atomic.
- */
- synchronized void setStatus(int svCount, int[] prns, float[] snrs,
- float[] elevations, float[] azimuths, int ephemerisMask,
- int almanacMask, int usedInFixMask) {
+ private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths, int[] constellationTypes) {
clearSatellites();
for (int i = 0; i < svCount; i++) {
- int prn = prns[i];
- int prnShift = (1 << (prn - 1));
+ // Skip all non-GPS satellites.
+ if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+ continue;
+ }
+ int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
if (prn > 0 && prn <= NUM_SATELLITES) {
GpsSatellite satellite = mSatellites.get(prn);
if (satellite == null) {
@@ -160,53 +158,26 @@
satellite.mSnr = snrs[i];
satellite.mElevation = elevations[i];
satellite.mAzimuth = azimuths[i];
- satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0);
- satellite.mHasAlmanac = ((almanacMask & prnShift) != 0);
- satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);
+ satellite.mHasEphemeris =
+ (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ satellite.mHasAlmanac =
+ (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ satellite.mUsedInFix =
+ (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
}
}
}
/**
- * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's
- * cached GpsStatus instance to the client's copy.
+ * Copies GPS satellites information from GnssStatus object.
* Since this method is only used within {@link LocationManager#getGpsStatus},
* it does not need to be synchronized.
+ * @hide
*/
- void setStatus(GpsStatus status) {
- mTimeToFirstFix = status.getTimeToFirstFix();
- clearSatellites();
-
- SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
- int otherSatellitesCount = otherSatellites.size();
- int satelliteIndex = 0;
- // merge both sparse arrays, note that we have already invalidated the elements in the
- // receiver array
- for (int i = 0; i < otherSatellitesCount; ++i) {
- GpsSatellite otherSatellite = otherSatellites.valueAt(i);
- int otherSatellitePrn = otherSatellite.getPrn();
-
- int satellitesCount = mSatellites.size();
- while (satelliteIndex < satellitesCount
- && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
- ++satelliteIndex;
- }
-
- if (satelliteIndex < mSatellites.size()) {
- GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
- if (satellite.getPrn() == otherSatellitePrn) {
- satellite.setStatus(otherSatellite);
- } else {
- satellite = new GpsSatellite(otherSatellitePrn);
- satellite.setStatus(otherSatellite);
- mSatellites.put(otherSatellitePrn, satellite);
- }
- } else {
- GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
- satellite.setStatus(otherSatellite);
- mSatellites.append(otherSatellitePrn, satellite);
- }
- }
+ void setStatus(GnssStatus status, int timeToFirstFix) {
+ mTimeToFirstFix = timeToFirstFix;
+ setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
+ status.mAzimuths, status.mConstellationTypes);
}
void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
similarity index 73%
rename from location/java/android/location/IGpsStatusListener.aidl
rename to location/java/android/location/IGnssStatusListener.aidl
index 62b1c6b..d1c6a85 100644
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -21,13 +21,12 @@
/**
* {@hide}
*/
-oneway interface IGpsStatusListener
+oneway interface IGnssStatusListener
{
- void onGpsStarted();
- void onGpsStopped();
+ void onGnssStarted();
+ void onGnssStopped();
void onFirstFix(int ttff);
- void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs,
- in float[] elevations, in float[] azimuths,
- int ephemerisMask, int almanacMask, int usedInFixMask);
+ void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
+ in float[] elevations, in float[] azimuths, in int[] constellationTypes);
void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/location/java/android/location/IGnssStatusProvider.aidl
similarity index 70%
rename from location/java/android/location/IGpsStatusProvider.aidl
rename to location/java/android/location/IGnssStatusProvider.aidl
index cf277c8..006b5d3 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/location/java/android/location/IGnssStatusProvider.aidl
@@ -16,14 +16,14 @@
package android.location;
-import android.location.IGpsStatusListener;
+import android.location.IGnssStatusListener;
/**
- * An interface for location providers that provide GPS status information.
+ * An interface for location providers that provide GNSS status information.
*
* {@hide}
*/
-interface IGpsStatusProvider {
- void addGpsStatusListener(IGpsStatusListener listener);
- void removeGpsStatusListener(IGpsStatusListener listener);
+interface IGnssStatusProvider {
+ void registerGnssStatusCallback(IGnssStatusListener callback);
+ void unregisterGnssStatusCallback(IGnssStatusListener callback);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index f3d755c..49d841f 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,9 +21,9 @@
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.IGnssStatusListener;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
import android.location.ILocationListener;
import android.location.Location;
import android.location.LocationRequest;
@@ -48,8 +48,8 @@
Location getLastLocation(in LocationRequest request, String packageName);
- boolean addGpsStatusListener(IGpsStatusListener listener, String packageName);
- void removeGpsStatusListener(IGpsStatusListener listener);
+ boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName);
+ void unregisterGnssStatusCallback(IGnssStatusListener callback);
boolean geocoderIsPresent();
String getFromLocation(double latitude, double longitude, int maxResults,
@@ -69,6 +69,8 @@
in String packageName);
void removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
+ int getGpsYearOfHardware();
+
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
index 458c451..d7d2c513 100644
--- a/location/java/android/location/LocalListenerHelper.java
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -20,12 +20,14 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
/**
* A base handler class to manage transport and local listeners.
@@ -33,7 +35,7 @@
* @hide
*/
abstract class LocalListenerHelper<TListener> {
- private final HashSet<TListener> mListeners = new HashSet<>();
+ private final HashMap<TListener, Handler> mListeners = new HashMap<>();
private final String mTag;
private final Context mContext;
@@ -44,7 +46,7 @@
mTag = name;
}
- public boolean add(@NonNull TListener listener) {
+ public boolean add(@NonNull TListener listener, Handler handler) {
Preconditions.checkNotNull(listener);
synchronized (mListeners) {
// we need to register with the service first, because we need to find out if the
@@ -62,17 +64,19 @@
return false;
}
}
- if (mListeners.contains(listener)) {
+ if (mListeners.containsKey(listener)) {
return true;
}
- return mListeners.add(listener);
+ mListeners.put(listener, handler);
+ return true;
}
}
public void remove(@NonNull TListener listener) {
Preconditions.checkNotNull(listener);
synchronized (mListeners) {
- boolean removed = mListeners.remove(listener);
+ boolean removed = mListeners.containsKey(listener);
+ mListeners.remove(listener);
boolean isLastRemoved = removed && mListeners.isEmpty();
if (isLastRemoved) {
try {
@@ -95,17 +99,30 @@
return mContext;
}
- protected void foreach(ListenerOperation<TListener> operation) {
- Collection<TListener> listeners;
- synchronized (mListeners) {
- listeners = new ArrayList<>(mListeners);
+ private void executeOperation(ListenerOperation<TListener> operation, TListener listener) {
+ try {
+ operation.execute(listener);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Error in monitored listener.", e);
+ // don't return, give a fair chance to all listeners to receive the event
}
- for (TListener listener : listeners) {
- try {
- operation.execute(listener);
- } catch (RemoteException e) {
- Log.e(mTag, "Error in monitored listener.", e);
- // don't return, give a fair chance to all listeners to receive the event
+ }
+
+ protected void foreach(final ListenerOperation<TListener> operation) {
+ Collection<Map.Entry<TListener, Handler>> listeners;
+ synchronized (mListeners) {
+ listeners = new ArrayList<>(mListeners.entrySet());
+ }
+ for (final Map.Entry<TListener, Handler> listener : listeners) {
+ if (listener.getValue() == null) {
+ executeOperation(operation, listener.getKey());
+ } else {
+ listener.getValue().post(new Runnable() {
+ @Override
+ public void run() {
+ executeOperation(operation, listener.getKey());
+ }
+ });
}
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2c19324..5447bb1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -20,6 +20,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -63,13 +64,18 @@
private final Context mContext;
private final ILocationManager mService;
- private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
- private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
- private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
- new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
- private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
- new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
- private final GpsStatus mGpsStatus = new GpsStatus();
+ private final GpsMeasurementCallbackTransport mGpsMeasurementCallbackTransport;
+ private final GpsNavigationMessageCallbackTransport mGpsNavigationMessageCallbackTransport;
+ private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
+ new HashMap<>();
+ private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
+ new HashMap<>();
+ private final HashMap<GnssStatusCallback, GnssStatusListenerTransport> mGnssStatusListeners =
+ new HashMap<>();
+ private final HashMap<GnssNmeaListener, GnssStatusListenerTransport> mGnssNmeaListeners =
+ new HashMap<>();
+ private GnssStatus mGnssStatus;
+ private int mTimeToFirstFix;
/**
* Name of the network location provider.
@@ -315,9 +321,9 @@
public LocationManager(Context context, ILocationManager service) {
mService = service;
mContext = context;
- mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
- mGpsNavigationMessageListenerTransport =
- new GpsNavigationMessageListenerTransport(mContext, mService);
+ mGpsMeasurementCallbackTransport = new GpsMeasurementCallbackTransport(mContext, mService);
+ mGpsNavigationMessageCallbackTransport =
+ new GpsNavigationMessageCallbackTransport(mContext, mService);
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1389,11 +1395,51 @@
// --- GPS-specific support ---
- // This class is used to send GPS status events to the client's main thread.
- private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
+ // This class is used to send Gnss status events to the client's specific thread.
+ private class GnssStatusListenerTransport extends IGnssStatusListener.Stub {
- private final GpsStatus.Listener mListener;
- private final GpsStatus.NmeaListener mNmeaListener;
+ private final GpsStatus.Listener mGpsListener;
+ private final GpsStatus.NmeaListener mGpsNmeaListener;
+ private final GnssStatusCallback mGnssCallback;
+ private final GnssNmeaListener mGnssNmeaListener;
+
+ private class GnssHandler extends Handler {
+ public GnssHandler(Handler handler) {
+ super(handler != null ? handler.getLooper() : Looper.myLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case NMEA_RECEIVED:
+ synchronized (mNmeaBuffer) {
+ int length = mNmeaBuffer.size();
+ for (int i = 0; i < length; i++) {
+ Nmea nmea = mNmeaBuffer.get(i);
+ mGnssNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+ }
+ mNmeaBuffer.clear();
+ }
+ break;
+ case GpsStatus.GPS_EVENT_STARTED:
+ mGnssCallback.onStarted();
+ break;
+ case GpsStatus.GPS_EVENT_STOPPED:
+ mGnssCallback.onStopped();
+ break;
+ case GpsStatus.GPS_EVENT_FIRST_FIX:
+ mGnssCallback.onFirstFix(mTimeToFirstFix);
+ break;
+ case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
+ mGnssCallback.onSatelliteStatusChanged(mGnssStatus);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private final Handler mGnssHandler;
// This must not equal any of the GpsStatus event IDs
private static final int NMEA_RECEIVED = 1000;
@@ -1407,97 +1453,141 @@
mNmea = nmea;
}
}
- private ArrayList<Nmea> mNmeaBuffer;
+ private final ArrayList<Nmea> mNmeaBuffer;
- GpsStatusListenerTransport(GpsStatus.Listener listener) {
- mListener = listener;
- mNmeaListener = null;
+ GnssStatusListenerTransport(GpsStatus.Listener listener) {
+ this(listener, null);
}
- GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
- mNmeaListener = listener;
- mListener = null;
+ GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) {
+ mGpsListener = listener;
+ mGnssHandler = new GnssHandler(handler);
+ mGpsNmeaListener = null;
+ mNmeaBuffer = null;
+ mGnssCallback = new GnssStatusCallback() {
+ @Override
+ public void onStarted() {
+ mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
+ }
+
+ @Override
+ public void onStopped() {
+ mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
+ }
+
+ @Override
+ public void onFirstFix(int ttff) {
+ mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
+ }
+
+ @Override
+ public void onSatelliteStatusChanged(GnssStatus status) {
+ mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+ }
+ };
+ mGnssNmeaListener = null;
+ }
+
+ GnssStatusListenerTransport(GpsStatus.NmeaListener listener) {
+ this(listener, null);
+ }
+
+ GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) {
+ mGpsListener = null;
+ mGnssHandler = new GnssHandler(handler);
+ mGpsNmeaListener = listener;
+ mNmeaBuffer = new ArrayList<Nmea>();
+ mGnssCallback = null;
+ mGnssNmeaListener = new GnssNmeaListener() {
+ @Override
+ public void onNmeaReceived(long timestamp, String nmea) {
+ mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
+ }
+ };
+ }
+
+ GnssStatusListenerTransport(GnssStatusCallback callback) {
+ this(callback, null);
+ }
+
+ GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
+ mGnssCallback = callback;
+ mGnssHandler = new GnssHandler(handler);
+ mGnssNmeaListener = null;
+ mNmeaBuffer = null;
+ mGpsListener = null;
+ mGpsNmeaListener = null;
+ }
+
+ GnssStatusListenerTransport(GnssNmeaListener listener) {
+ this(listener, null);
+ }
+
+ GnssStatusListenerTransport(GnssNmeaListener listener, Handler handler) {
+ mGnssCallback = null;
+ mGnssHandler = new GnssHandler(handler);
+ mGnssNmeaListener = listener;
+ mGpsListener = null;
+ mGpsNmeaListener = null;
mNmeaBuffer = new ArrayList<Nmea>();
}
@Override
- public void onGpsStarted() {
- if (mListener != null) {
+ public void onGnssStarted() {
+ if (mGpsListener != null) {
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_STARTED;
- mGpsHandler.sendMessage(msg);
+ mGnssHandler.sendMessage(msg);
}
}
@Override
- public void onGpsStopped() {
- if (mListener != null) {
+ public void onGnssStopped() {
+ if (mGpsListener != null) {
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_STOPPED;
- mGpsHandler.sendMessage(msg);
+ mGnssHandler.sendMessage(msg);
}
}
@Override
public void onFirstFix(int ttff) {
- if (mListener != null) {
- mGpsStatus.setTimeToFirstFix(ttff);
+ if (mGpsListener != null) {
+ mTimeToFirstFix = ttff;
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
- mGpsHandler.sendMessage(msg);
+ mGnssHandler.sendMessage(msg);
}
}
@Override
- public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
- float[] elevations, float[] azimuths, int ephemerisMask,
- int almanacMask, int usedInFixMask) {
- if (mListener != null) {
- mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
- ephemerisMask, almanacMask, usedInFixMask);
+ public void onSvStatusChanged(int svCount, int[] prnWithFlags,
+ float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+ if (mGnssCallback != null) {
+ mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
+ constellationTypes);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
// remove any SV status messages already in the queue
- mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
- mGpsHandler.sendMessage(msg);
+ mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+ mGnssHandler.sendMessage(msg);
}
}
@Override
public void onNmeaReceived(long timestamp, String nmea) {
- if (mNmeaListener != null) {
+ if (mGnssNmeaListener != null) {
synchronized (mNmeaBuffer) {
mNmeaBuffer.add(new Nmea(timestamp, nmea));
}
Message msg = Message.obtain();
msg.what = NMEA_RECEIVED;
// remove any NMEA_RECEIVED messages already in the queue
- mGpsHandler.removeMessages(NMEA_RECEIVED);
- mGpsHandler.sendMessage(msg);
+ mGnssHandler.removeMessages(NMEA_RECEIVED);
+ mGnssHandler.sendMessage(msg);
}
}
-
- private final Handler mGpsHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NMEA_RECEIVED) {
- synchronized (mNmeaBuffer) {
- int length = mNmeaBuffer.size();
- for (int i = 0; i < length; i++) {
- Nmea nmea = mNmeaBuffer.get(i);
- mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
- }
- mNmeaBuffer.clear();
- }
- } else {
- // synchronize on mGpsStatus to ensure the data is copied atomically.
- synchronized(mGpsStatus) {
- mListener.onGpsStatusChanged(msg.what);
- }
- }
- }
- };
}
/**
@@ -1508,7 +1598,9 @@
* @return true if the listener was successfully added
*
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ * @deprecated use {@link #registerGnssStatusCallback(GnssStatusCallback)} instead.
*/
+ @Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
boolean result;
@@ -1518,8 +1610,8 @@
return true;
}
try {
- GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
- result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+ GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+ result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
if (result) {
mGpsStatusListeners.put(listener, transport);
}
@@ -1536,17 +1628,81 @@
*
* @param listener GPS status listener object to remove
*/
+ @Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
try {
- GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
+ GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
if (transport != null) {
- mService.removeGpsStatusListener(transport);
+ mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
}
}
+
+ /**
+ * Registers a GNSS status listener.
+ *
+ * @param callback GNSS status listener object to register
+ *
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ */
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGnssStatusCallback(GnssStatusCallback callback) {
+ return registerGnssStatusCallback(callback, null);
+ }
+
+ /**
+ * Registers a GNSS status listener.
+ *
+ * @param callback GNSS status listener object to register
+ * @param handler the handler that the callback runs on.
+ *
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ */
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGnssStatusCallback(GnssStatusCallback callback, Handler handler) {
+ boolean result;
+ if (mGnssStatusListeners.get(callback) != null) {
+ // listener is already registered
+ return true;
+ }
+ try {
+ GnssStatusListenerTransport transport =
+ new GnssStatusListenerTransport(callback, handler);
+ result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+ if (result) {
+ mGnssStatusListeners.put(callback, transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Removes a GNSS status listener.
+ *
+ * @param callback GNSS status listener object to remove
+ */
+ public void unregisterGnssStatusCallback(GnssStatusCallback callback) {
+ try {
+ GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback);
+ if (transport != null) {
+ mService.unregisterGnssStatusCallback(transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+ }
+ }
+
/**
* Adds an NMEA listener.
*
@@ -1555,20 +1711,22 @@
* @return true if the listener was successfully added
*
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ * @deprecated use {@link #addNmeaListener(GnssNmeaListener)} instead.
*/
+ @Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
boolean result;
- if (mNmeaListeners.get(listener) != null) {
+ if (mGpsNmeaListeners.get(listener) != null) {
// listener is already registered
return true;
}
try {
- GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
- result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+ GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+ result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
if (result) {
- mNmeaListeners.put(listener, transport);
+ mGpsNmeaListeners.put(listener, transport);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
@@ -1583,11 +1741,12 @@
*
* @param listener a {@link GpsStatus.NmeaListener} object to remove
*/
+ @Deprecated
public void removeNmeaListener(GpsStatus.NmeaListener listener) {
try {
- GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+ GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener);
if (transport != null) {
- mService.removeGpsStatusListener(transport);
+ mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
@@ -1595,54 +1754,133 @@
}
/**
- * Adds a GPS Measurement listener.
+ * Adds an NMEA listener.
*
- * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
- * @return {@code true} if the listener was added successfully, {@code false} otherwise.
+ * @param listener a {@link GnssNmeaListener} object to register
*
- * @hide
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
- @SystemApi
- public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
- return mGpsMeasurementListenerTransport.add(listener);
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean addNmeaListener(GnssNmeaListener listener) {
+ return addNmeaListener(listener, null);
}
/**
- * Removes a GPS Measurement listener.
+ * Adds an NMEA listener.
*
- * @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.
+ * @param listener a {@link GnssNmeaListener} object to register
+ * @param handler the handler that the listener runs on.
*
- * @hide
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
- @SystemApi
- public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
- mGpsMeasurementListenerTransport.remove(listener);
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean addNmeaListener(GnssNmeaListener listener, Handler handler) {
+ boolean result;
+
+ if (mGpsNmeaListeners.get(listener) != null) {
+ // listener is already registered
+ return true;
+ }
+ try {
+ GnssStatusListenerTransport transport =
+ new GnssStatusListenerTransport(listener, handler);
+ result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+ if (result) {
+ mGnssNmeaListeners.put(listener, transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+ result = false;
+ }
+
+ return result;
}
/**
- * Adds a GPS Navigation Message listener.
+ * Removes an NMEA listener.
*
- * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
- * @return {@code true} if the listener was added successfully, {@code false} otherwise.
- *
- * @hide
+ * @param listener a {@link GnssNmeaListener} object to remove
*/
- @SystemApi
- public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
- return mGpsNavigationMessageListenerTransport.add(listener);
+ public void removeNmeaListener(GnssNmeaListener listener) {
+ try {
+ GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener);
+ if (transport != null) {
+ mService.unregisterGnssStatusCallback(transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+ }
}
/**
- * Removes a GPS Navigation Message listener.
+ * Registers a GPS Measurement callback.
*
- * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
- *
- * @hide
+ * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+ * @return {@code true} if the callback was added successfully, {@code false} otherwise.
*/
- @SystemApi
- public void removeGpsNavigationMessageListener(
- GpsNavigationMessageEvent.Listener listener) {
- mGpsNavigationMessageListenerTransport.remove(listener);
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+ return registerGpsMeasurementCallback(callback, null);
+ }
+
+ /**
+ * Registers a GPS Measurement callback.
+ *
+ * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+ * @param handler the handler that the callback runs on.
+ * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ */
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback,
+ Handler handler) {
+ return mGpsMeasurementCallbackTransport.add(callback, handler);
+ }
+
+ /**
+ * Unregisters a GPS Measurement callback.
+ *
+ * @param callback a {@link GpsMeasurementsEvent.Callback} object to remove.
+ */
+ public void unregisterGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+ mGpsMeasurementCallbackTransport.remove(callback);
+ }
+
+ /**
+ * Registers a GPS Navigation Message callback.
+ *
+ * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+ * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ */
+ public boolean registerGpsNavigationMessageCallback(
+ GpsNavigationMessageEvent.Callback callback) {
+ return registerGpsNavigationMessageCallback(callback, null);
+ }
+
+ /**
+ * Registers a GPS Navigation Message callback.
+ *
+ * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+ * @param handler the handler that the callback runs on.
+ * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ */
+ @RequiresPermission(ACCESS_FINE_LOCATION)
+ public boolean registerGpsNavigationMessageCallback(
+ GpsNavigationMessageEvent.Callback callback, Handler handler) {
+ return mGpsNavigationMessageCallbackTransport.add(callback, handler);
+ }
+
+ /**
+ * Unregisters a GPS Navigation Message callback.
+ *
+ * @param callback a {@link GpsNavigationMessageEvent.Callback} object to remove.
+ */
+ public void unregisterGpsNavigationMessageCallback(
+ GpsNavigationMessageEvent.Callback callback) {
+ mGpsNavigationMessageCallbackTransport.remove(callback);
}
/**
@@ -1656,15 +1894,36 @@
* @param status object containing GPS status details, or null.
* @return status object containing updated GPS status.
*/
+ @Deprecated
+ @RequiresPermission(ACCESS_FINE_LOCATION)
public GpsStatus getGpsStatus(GpsStatus status) {
if (status == null) {
status = new GpsStatus();
}
- status.setStatus(mGpsStatus);
+ // When mGnssStatus is null, that means that this method is called outside
+ // onGpsStatusChanged(). Return an empty status to maintain backwards compatibility.
+ if (mGnssStatus != null) {
+ status.setStatus(mGnssStatus, mTimeToFirstFix);
+ }
return status;
}
/**
+ * Returns the system information of the GPS hardware.
+ * May return 0 if GPS hardware is earlier than 2016.
+ * @hide
+ */
+ @TestApi
+ public int getGpsYearOfHardware() {
+ try {
+ return mService.getGpsYearOfHardware();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getGpsSystemInfo: ", e);
+ return 0;
+ }
+ }
+
+ /**
* Sends additional commands to a location provider.
* Can be used to support provider specific extensions to the Location Manager API
*
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 260f380..93e86af 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -62,7 +62,7 @@
public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
- // the extra command to send NI response to GpsLocationProvider
+ // the extra command to send NI response to GnssLocationProvider
public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
// the extra command parameter names in the Bundle
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index efae628..c194711 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -224,7 +224,6 @@
public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
/**
- * @hide
* Flag requesting a low latency path.
* When using this flag, the sample rate must match the native sample rate
* of the device. Effects processing is also unavailable.
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index bde3d19..000a56d 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -251,6 +251,10 @@
* @hide
* */
public static final int ENCODING_AAC_HE_V2 = 12;
+ /** Audio data format: compressed audio wrapped in PCM for HDMI
+ * or S/PDIF passthrough.
+ */
+ public static final int ENCODING_IEC61937 = 13;
/** Invalid audio channel configuration */
/** @deprecated Use {@link #CHANNEL_INVALID} instead. */
@@ -418,6 +422,7 @@
case ENCODING_PCM_8BIT:
return 1;
case ENCODING_PCM_16BIT:
+ case ENCODING_IEC61937:
case ENCODING_DEFAULT:
return 2;
case ENCODING_PCM_FLOAT:
@@ -443,6 +448,7 @@
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
+ case ENCODING_IEC61937:
return true;
default:
return false;
@@ -460,6 +466,7 @@
case ENCODING_E_AC3:
case ENCODING_DTS:
case ENCODING_DTS_HD:
+ case ENCODING_IEC61937:
return true;
default:
return false;
@@ -483,6 +490,7 @@
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
+ case ENCODING_IEC61937: // wrapped in PCM but compressed
return false;
case ENCODING_INVALID:
default:
@@ -490,6 +498,30 @@
}
}
+ /** @hide */
+ public static boolean isEncodingLinearFrames(int audioFormat)
+ {
+ switch (audioFormat) {
+ case ENCODING_PCM_8BIT:
+ case ENCODING_PCM_16BIT:
+ case ENCODING_PCM_FLOAT:
+ case ENCODING_IEC61937: // same size as stereo PCM
+ case ENCODING_DEFAULT:
+ return true;
+ case ENCODING_AC3:
+ case ENCODING_E_AC3:
+ case ENCODING_DTS:
+ case ENCODING_DTS_HD:
+ case ENCODING_MP3:
+ case ENCODING_AAC_LC:
+ case ENCODING_AAC_HE_V1:
+ case ENCODING_AAC_HE_V2:
+ return false;
+ case ENCODING_INVALID:
+ default:
+ throw new IllegalArgumentException("Bad audio format " + audioFormat);
+ }
+ }
/**
* Returns an array of public encoding values extracted from an array of
* encoding values.
@@ -715,6 +747,7 @@
case ENCODING_E_AC3:
case ENCODING_DTS:
case ENCODING_DTS_HD:
+ case ENCODING_IEC61937:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -859,7 +892,8 @@
ENCODING_AC3,
ENCODING_E_AC3,
ENCODING_DTS,
- ENCODING_DTS_HD
+ ENCODING_DTS_HD,
+ ENCODING_IEC61937
})
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7c21893..800b914 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -826,6 +826,33 @@
}
/**
+ * Poll for an {@link AudioTimestamp} on demand.
+ * <p>
+ * The AudioTimestamp reflects the frame delivery information at
+ * the earliest point available in the capture pipeline.
+ * <p>
+ * Calling {@link #startRecording()} following a {@link #stop()} will reset
+ * the frame count to 0.
+ *
+ * @param timestamp a reference to a non-null AudioTimestamp instance.
+ * @param timebase one of
+ * {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
+ * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}.
+ * @return {@link #SUCCESS} if a timestamp is available,
+ * or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
+ */
+ public int getTimestamp(@NonNull AudioTimestamp timestamp,
+ @AudioTimestamp.Timebase int timebase)
+ {
+ if (timestamp == null ||
+ (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
+ && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
+ throw new IllegalArgumentException();
+ }
+ return native_get_timestamp(timestamp, timebase);
+ }
+
+ /**
* Returns the minimum buffer size required for the successful creation of an AudioRecord
* object, in byte units.
* Note that this size doesn't guarantee a smooth recording under load, and higher values
@@ -1709,6 +1736,9 @@
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
+ private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp,
+ @AudioTimestamp.Timebase int timebase);
+
//---------------------------------------------------------
// Utility methods
//------------------
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
index c7d219d..69df88f 100644
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -23,7 +23,7 @@
/**
* The AudioRecordConfiguration class collects the information describing an audio recording
- * session. This information is returned through the
+ * session. This information is returned through the
* {@link AudioManager#getActiveRecordConfigurations()} method.
*
*/
@@ -33,12 +33,32 @@
private final int mClientSource;
+ private final AudioFormat mDeviceFormat;
+ private final AudioFormat mClientFormat;
+
+ private final AudioDeviceInfo mRecDevice;
+
/**
* @hide
*/
public AudioRecordConfiguration(int session, int source) {
mSessionId = session;
mClientSource = source;
+ mDeviceFormat = new AudioFormat.Builder().build();
+ mClientFormat = new AudioFormat.Builder().build();
+ mRecDevice = null;
+ }
+
+ /**
+ * @hide
+ */
+ public AudioRecordConfiguration(int session, int source, AudioFormat devFormat,
+ AudioFormat clientFormat, AudioDeviceInfo device) {
+ mSessionId = session;
+ mClientSource = source;
+ mDeviceFormat = devFormat;
+ mClientFormat = clientFormat;
+ mRecDevice = device;
}
/**
@@ -57,7 +77,28 @@
* Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
* @return the session number.
*/
- public int getAudioSessionId() { return mSessionId; }
+ public int getClientAudioSessionId() { return mSessionId; }
+
+ /**
+ * Returns the audio format at which audio is recorded on this Android device.
+ * Note that it may differ from the client application recording format
+ * (see {@link #getClientFormat()}).
+ * @return the device recording format
+ */
+ public AudioFormat getFormat() { return mDeviceFormat; }
+
+ /**
+ * Returns the audio format at which the client application is recording audio.
+ * Note that it may differ from the actual recording format (see {@link #getFormat()}).
+ * @return the recording format
+ */
+ public AudioFormat getClientFormat() { return mClientFormat; }
+
+ /**
+ * Returns the audio input device used for this recording.
+ * @return the audio recording device
+ */
+ public AudioDeviceInfo getAudioDevice() { return mRecDevice; }
public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
= new Parcelable.Creator<AudioRecordConfiguration>() {
@@ -93,6 +134,9 @@
private AudioRecordConfiguration(Parcel in) {
mSessionId = in.readInt();
mClientSource = in.readInt();
+ mDeviceFormat = new AudioFormat.Builder().build();
+ mClientFormat = new AudioFormat.Builder().build();
+ mRecDevice = null;
}
@Override
diff --git a/media/java/android/media/AudioTimestamp.java b/media/java/android/media/AudioTimestamp.java
index 965ba85..be8ca15 100644
--- a/media/java/android/media/AudioTimestamp.java
+++ b/media/java/android/media/AudioTimestamp.java
@@ -16,29 +16,74 @@
package android.media;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
+
/**
* Structure that groups a position in frame units relative to an assumed audio stream,
- * together with the estimated time when that frame was presented or is committed to be
- * presented.
- * In the case of audio output, "present" means that audio produced on device
- * is detectable by an external observer off device.
+ * together with the estimated time when that frame enters or leaves the audio
+ * processing pipeline on that device. This can be used to coordinate events
+ * and interactions with the external environment.
+ * <p>
* The time is based on the implementation's best effort, using whatever knowledge
* is available to the system, but cannot account for any delay unknown to the implementation.
*
- * @see AudioTrack#getTimestamp
+ * @see AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)
+ * @see AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)
*/
public final class AudioTimestamp
{
/**
+ * Clock monotonic or its equivalent on the system,
+ * in the same units and timebase as {@link java.lang.System#nanoTime}.
+ */
+ public static final int TIMEBASE_MONOTONIC = 0;
+
+ /**
+ * Clock monotonic including suspend time or its equivalent on the system,
+ * in the same units and timebase as {@link android.os.SystemClock#elapsedRealtimeNanos}.
+ */
+ public static final int TIMEBASE_BOOTTIME = 1;
+
+ /** @hide */
+ @IntDef({
+ TIMEBASE_MONOTONIC,
+ TIMEBASE_BOOTTIME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Timebase {}
+
+ /**
* Position in frames relative to start of an assumed audio stream.
- * The low-order 32 bits of position is in wrapping frame units similar to
- * {@link AudioTrack#getPlaybackHeadPosition}.
+ * <p>
+ * When obtained through
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+ * all 64 bits of position are valid.
+ * <p>
+ * When obtained through
+ * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+ * the low-order 32 bits of position is in wrapping frame units similar to
+ * {@link AudioTrack#getPlaybackHeadPosition AudioTrack.getPlaybackHeadPosition()}.
*/
public long framePosition;
/**
- * The estimated time when frame was presented or is committed to be presented,
- * in the same units and timebase as {@link java.lang.System#nanoTime}.
+ * Time associated with the frame in the audio pipeline.
+ * <p>
+ * When obtained through
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+ * this is the estimated time in nanoseconds when the frame referred to by
+ * {@link #framePosition} was captured. The timebase is either
+ * {@link #TIMEBASE_MONOTONIC} or {@link #TIMEBASE_BOOTTIME}, depending
+ * on the timebase parameter used in
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)}.
+ * <p>
+ * When obtained through
+ * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+ * this is the estimated time when the frame was presented or is committed to be presented,
+ * with a timebase of {@link #TIMEBASE_MONOTONIC}.
*/
public long nanoTime;
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 4319840..3007d86 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1100,7 +1100,6 @@
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
* {@link #ERROR_INVALID_OPERATION}
* @throws IllegalStateException
- * @hide
*/
public int setBufferSizeInFrames(int bufferSizeInFrames) {
if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
@@ -1130,7 +1129,6 @@
* {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
* @return maximum size in frames of the <code>AudioTrack</code> buffer.
* @throws IllegalStateException
- * @hide
*/
public int getBufferCapacityInFrames() {
return native_get_buffer_capacity_frames();
@@ -1204,7 +1202,6 @@
* This is a continuously advancing counter. It can wrap around to zero
* if there are too many underruns. If there were, for example, 68 underruns per
* second then the counter would wrap in 2 years.
- * @hide
*/
public int getUnderrunCount() {
return native_get_underrun_count();
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
new file mode 100644
index 0000000..06fe6ff
--- /dev/null
+++ b/media/java/android/media/DrmInitData.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+import android.media.MediaDrm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Encapsulates initialization data required by a {@link MediaDrm} instance.
+ */
+public abstract class DrmInitData {
+
+ /**
+ * Retrieves initialization data for a given DRM scheme, specified by its UUID.
+ *
+ * @param schemeUuid The DRM scheme's UUID.
+ * @return The initialization data for the scheme, or null if the scheme is not supported.
+ */
+ public abstract SchemeInitData get(UUID schemeUuid);
+
+ /**
+ * Scheme initialization data.
+ */
+ public static final class SchemeInitData {
+
+ /**
+ * The mimeType of {@link #data}.
+ */
+ public final String mimeType;
+ /**
+ * The initialization data.
+ */
+ public final byte[] data;
+
+ /**
+ * @param mimeType The mimeType of the initialization data.
+ * @param data The initialization data.
+ *
+ * @hide
+ */
+ public SchemeInitData(String mimeType, byte[] data) {
+ this.mimeType = mimeType;
+ this.data = data;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SchemeInitData)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+
+ SchemeInitData other = (SchemeInitData) obj;
+ return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return mimeType.hashCode() + 31 * Arrays.hashCode(data);
+ }
+
+ }
+
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 331fde1..d9690f0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1735,7 +1735,7 @@
}
private void applyLevelLimits() {
- int maxBlocksPerSecond = 0;
+ long maxBlocksPerSecond = 0;
int maxBlocks = 0;
int maxBps = 0;
int maxDPBBlocks = 0;
@@ -2061,11 +2061,11 @@
16 /* blockWidth */, 16 /* blockHeight */,
1 /* widthAlignment */, 1 /* heightAlignment */);
mFrameRateRange = Range.create(1, maxRate);
- } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
- mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE;
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
+ maxBlocks = Integer.MAX_VALUE;
+ maxBlocksPerSecond = Integer.MAX_VALUE;
- // TODO: set to 100Mbps for now, need a number for VPX
+ // TODO: set to 100Mbps for now, need a number for VP8
maxBps = 100000000;
// profile levels are not indicative for VPx, but verify
@@ -2093,11 +2093,80 @@
errors &= ~ERROR_NONE_SUPPORTED;
}
- final int blockSize =
- mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
+ final int blockSize = 16;
applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
1 /* widthAlignment */, 1 /* heightAlignment */);
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+ maxBlocksPerSecond = 829440;
+ maxBlocks = 36864;
+ maxBps = 200000;
+
+ for (CodecProfileLevel profileLevel: profileLevels) {
+ long SR = 0;
+ int FS = 0;
+ int BR = 0;
+ switch (profileLevel.level) {
+ case CodecProfileLevel.VP9Level1:
+ SR = 829440; FS = 36864; BR = 200; break;
+ case CodecProfileLevel.VP9Level11:
+ SR = 2764800; FS = 73728; BR = 800; break;
+ case CodecProfileLevel.VP9Level2:
+ SR = 4608000; FS = 122880; BR = 1800; break;
+ case CodecProfileLevel.VP9Level21:
+ SR = 9216000; FS = 245760; BR = 3600; break;
+ case CodecProfileLevel.VP9Level3:
+ SR = 20736000; FS = 552960; BR = 7200; break;
+ case CodecProfileLevel.VP9Level31:
+ SR = 36864000; FS = 983040; BR = 12000; break;
+ case CodecProfileLevel.VP9Level4:
+ SR = 83558400; FS = 2228224; BR = 18000; break;
+ case CodecProfileLevel.VP9Level41:
+ SR = 160432128; FS = 2228224; BR = 30000; break;
+ case CodecProfileLevel.VP9Level5:
+ SR = 311951360; FS = 8912896; BR = 60000; break;
+ case CodecProfileLevel.VP9Level51:
+ SR = 588251136; FS = 8912896; BR = 120000; break;
+ case CodecProfileLevel.VP9Level52:
+ SR = 1176502272; FS = 8912896; BR = 180000; break;
+ case CodecProfileLevel.VP9Level6:
+ SR = 1176502272; FS = 35651584; BR = 180000; break;
+ case CodecProfileLevel.VP9Level61:
+ SR = 2353004544L; FS = 35651584; BR = 240000; break;
+ case CodecProfileLevel.VP9Level62:
+ SR = 4706009088L; FS = 35651584; BR = 480000; break;
+ default:
+ Log.w(TAG, "Unrecognized level "
+ + profileLevel.level + " for " + mime);
+ errors |= ERROR_UNRECOGNIZED;
+ }
+ switch (profileLevel.profile) {
+ case CodecProfileLevel.VP9Profile0:
+ case CodecProfileLevel.VP9Profile1:
+ case CodecProfileLevel.VP9Profile2:
+ case CodecProfileLevel.VP9Profile3:
+ break;
+ default:
+ Log.w(TAG, "Unrecognized profile "
+ + profileLevel.profile + " for " + mime);
+ errors |= ERROR_UNRECOGNIZED;
+ }
+ errors &= ~ERROR_NONE_SUPPORTED;
+ maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
+ maxBlocks = Math.max(FS, maxBlocks);
+ maxBps = Math.max(BR * 1000, maxBps);
+ }
+
+ final int blockSize = 8;
+ int maxLengthInBlocks = Utils.divUp(maxBlocks, blockSize);
+ maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
+ maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
+
+ applyMacroBlockLimits(
+ maxLengthInBlocks, maxLengthInBlocks,
+ maxBlocks, maxBlocksPerSecond,
+ blockSize, blockSize,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
maxBlocks = 36864;
maxBlocksPerSecond = maxBlocks * 15;
@@ -2540,6 +2609,28 @@
// from OMX_VIDEO_VP8PROFILETYPE
public static final int VP8ProfileMain = 0x01;
+ // from OMX_VIDEO_VP9PROFILETYPE
+ public static final int VP9Profile0 = 0x00;
+ public static final int VP9Profile1 = 0x01;
+ public static final int VP9Profile2 = 0x02;
+ public static final int VP9Profile3 = 0x03;
+
+ // from OMX_VIDEO_VP9LEVELTYPE
+ public static final int VP9Level1 = 0x0;
+ public static final int VP9Level11 = 0x1;
+ public static final int VP9Level2 = 0x2;
+ public static final int VP9Level21 = 0x4;
+ public static final int VP9Level3 = 0x8;
+ public static final int VP9Level31 = 0x10;
+ public static final int VP9Level4 = 0x20;
+ public static final int VP9Level41 = 0x40;
+ public static final int VP9Level5 = 0x80;
+ public static final int VP9Level51 = 0x100;
+ public static final int VP9Level52 = 0x200;
+ public static final int VP9Level6 = 0x400;
+ public static final int VP9Level61 = 0x800;
+ public static final int VP9Level62 = 0x1000;
+
// from OMX_VIDEO_HEVCPROFILETYPE
public static final int HEVCProfileMain = 0x01;
public static final int HEVCProfileMain10 = 0x02;
@@ -2594,14 +2685,18 @@
/**
* Defined in the OpenMAX IL specs, depending on the type of media
* this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
- * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
+ * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
*/
public int profile;
/**
* Defined in the OpenMAX IL specs, depending on the type of media
* this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
- * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
+ * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+ *
+ * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
+ * not advertise a profile level support. For those VP9 decoders, please use
+ * {@link VideoCapabilities} to determine the codec capabilities.
*/
public int level;
};
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 0bf995f..b339925 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -34,7 +34,9 @@
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -226,6 +228,46 @@
public native final int getTrackCount();
/**
+ * Extract DRM initialization data if it exists
+ *
+ * @return DRM initialization data in the content, or {@code null}
+ * if no recognizable DRM format is found;
+ * @see DrmInitData
+ */
+ public DrmInitData getDrmInitData() {
+ Map<String, Object> formatMap = getFileFormatNative();
+ if (formatMap == null) {
+ return null;
+ }
+ if (formatMap.containsKey("pssh")) {
+ Map<UUID, byte[]> psshMap = getPsshInfo();
+ final Map<UUID, DrmInitData.SchemeInitData> initDataMap =
+ new HashMap<UUID, DrmInitData.SchemeInitData>();
+ for (Map.Entry<UUID, byte[]> e: psshMap.entrySet()) {
+ UUID uuid = e.getKey();
+ byte[] data = e.getValue();
+ initDataMap.put(uuid, new DrmInitData.SchemeInitData("cenc", data));
+ }
+ return new DrmInitData() {
+ public SchemeInitData get(UUID schemeUuid) {
+ return initDataMap.get(schemeUuid);
+ }
+ };
+ } else if (formatMap.containsKey("crypto-key")) {
+ ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
+ buf.rewind();
+ final byte[] data = new byte[buf.remaining()];
+ buf.get(data);
+ return new DrmInitData() {
+ public SchemeInitData get(UUID schemeUuid) {
+ return new DrmInitData.SchemeInitData("webm", data);
+ }
+ };
+ }
+ return null;
+ }
+
+ /**
* Get the PSSH info if present.
* @return a map of uuid-to-bytes, with the uuid specifying
* the crypto scheme, and the bytes being the data specific to that scheme.
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 930d8b8..d06da97 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -563,6 +563,66 @@
/** @hide */
public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
+ // The following color aspect values must be in sync with the ones in HardwareAPI.h.
+ /*
+ * An optional key describing the color primaries, white point and
+ * luminance factors for video content.
+ *
+ * The associated value is an integer: 0 if unspecified, or one of the
+ * COLOR_STANDARD_ values.
+ */
+ public static final String KEY_COLOR_STANDARD = "color-standard";
+
+ /** BT.709 color chromacity coordinates with KR = 0.2126, KB = 0.0722. */
+ public static final int COLOR_STANDARD_BT709 = 1;
+
+ /** BT.601 625 color chromacity coordinates with KR = 0.299, KB = 0.114. */
+ public static final int COLOR_STANDARD_BT601_PAL = 2;
+
+ /** BT.601 525 color chromacity coordinates with KR = 0.299, KB = 0.114. */
+ public static final int COLOR_STANDARD_BT601_NTSC = 4;
+
+ /** BT.2020 color chromacity coordinates with KR = 0.2627, KB = 0.0593. */
+ public static final int COLOR_STANDARD_BT2020 = 6;
+
+ /**
+ * An optional key describing the opto-electronic transfer function used
+ * for the video content.
+ *
+ * The associated value is an integer: 0 if unspecified, or one of the
+ * COLOR_TRANSFER_ values.
+ */
+ public static final String KEY_COLOR_TRANSFER = "color-transfer";
+
+ /** Linear transfer characteristic curve. */
+ public static final int COLOR_TRANSFER_LINEAR = 1;
+
+ /** SMPTE 170M transfer characteristic curve used by BT.601/BT.709/BT.2020. This is the curve
+ * used by most non-HDR video content. */
+ public static final int COLOR_TRANSFER_SDR_VIDEO = 3;
+
+ /** SMPTE ST 2084 transfer function. This is used by some HDR video content. */
+ public static final int COLOR_TRANSFER_ST2084 = 6;
+
+ /** ARIB STD-B67 hybrid-log-gamma transfer function. This is used by some HDR video content. */
+ public static final int COLOR_TRANSFER_HLG = 7;
+
+ /**
+ * An optional key describing the range of the component values of the video content.
+ *
+ * The associated value is an integer: 0 if unspecified, or one of the
+ * COLOR_RANGE_ values.
+ */
+ public static final String KEY_COLOR_RANGE = "color-range";
+
+ /** Limited range. Y component values range from 16 to 235 for 8-bit content.
+ * Cr, Cy values range from 16 to 240 for 8-bit content.
+ * This is the default for video content. */
+ public static final int COLOR_RANGE_LIMITED = 2;
+
+ /** Full range. Y, Cr and Cb component values range from 0 to 255 for 8-bit content. */
+ public static final int COLOR_RANGE_FULL = 1;
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 2cd3c43..35b083e 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -174,7 +174,7 @@
return (num + den - 1) / den;
}
- private static long divUp(long num, long den) {
+ static long divUp(long num, long den) {
return (num + den - 1) / den;
}
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 02b03d2..f9fdd8d 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -19,6 +19,7 @@
import android.annotation.SystemApi;
import android.media.AudioAttributes;
import android.os.Parcel;
+import android.util.Log;
import java.util.ArrayList;
import java.util.Iterator;
@@ -48,14 +49,27 @@
/**
* A rule requiring the usage information of the {@link AudioAttributes} to match.
+ * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+ * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+ * {@link AudioAttributes}.
*/
@SystemApi
public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1;
/**
* A rule requiring the capture preset information of the {@link AudioAttributes} to match.
+ * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+ * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+ * {@link AudioAttributes}.
*/
@SystemApi
public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1;
+ /**
+ * A rule requiring the UID of the audio stream to match that specified.
+ * This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
+ * parameter is an instance of {@link java.lang.Integer}.
+ */
+ @SystemApi
+ public static final int RULE_MATCH_UID = 0x1 << 2;
private final static int RULE_EXCLUSION_MASK = 0x8000;
/**
@@ -70,29 +84,53 @@
*/
public static final int RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET =
RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
+ /**
+ * @hide
+ * A rule requiring the UID information to differ.
+ */
+ public static final int RULE_EXCLUDE_UID =
+ RULE_EXCLUSION_MASK | RULE_MATCH_UID;
static final class AttributeMatchCriterion {
- AudioAttributes mAttr;
- int mRule;
+ final AudioAttributes mAttr;
+ final Integer mIntProp;
+ final int mRule;
/** input parameters must be valid */
AttributeMatchCriterion(AudioAttributes attributes, int rule) {
mAttr = attributes;
+ mIntProp = null;
+ mRule = rule;
+ }
+ /** input parameters must be valid */
+ AttributeMatchCriterion(Integer intProp, int rule) {
+ mAttr = null;
+ mIntProp = intProp;
mRule = rule;
}
@Override
public int hashCode() {
- return Objects.hash(mAttr, mRule);
+ return Objects.hash(mAttr, mIntProp, mRule);
}
void writeToParcel(Parcel dest) {
dest.writeInt(mRule);
- if ((mRule == RULE_MATCH_ATTRIBUTE_USAGE) || (mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
+ final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
dest.writeInt(mAttr.getUsage());
- } else {
- // capture preset rule
+ break;
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
dest.writeInt(mAttr.getCapturePreset());
+ break;
+ case RULE_MATCH_UID:
+ dest.writeInt(mIntProp.intValue());
+ break;
+ default:
+ Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+ + " when writing to Parcel");
+ dest.writeInt(-1);
}
}
}
@@ -108,7 +146,19 @@
}
private static boolean isValidSystemApiRule(int rule) {
- switch(rule) {
+ // API rules only expose the RULE_MATCH_* rules
+ switch (rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ case RULE_MATCH_UID:
+ return true;
+ default:
+ return false;
+ }
+ }
+ private static boolean isValidAttributesSystemApiRule(int rule) {
+ // API rules only expose the RULE_MATCH_* rules
+ switch (rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
return true;
@@ -117,12 +167,12 @@
}
}
- private static boolean isValidIntRule(int rule) {
- switch(rule) {
+ private static boolean isValidRule(int rule) {
+ final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
- case RULE_EXCLUDE_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
+ case RULE_MATCH_UID:
return true;
default:
return false;
@@ -130,8 +180,24 @@
}
private static boolean isPlayerRule(int rule) {
- return ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
- || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE));
+ final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_UID:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isAudioAttributeRule(int match_rule) {
+ switch(match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ return true;
+ default:
+ return false;
+ }
}
/**
@@ -158,14 +224,15 @@
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
* @return the same Builder instance.
* @throws IllegalArgumentException
+ * @see {@link #excludeRule(AudioAttributes, int)}
*/
@SystemApi
public Builder addRule(AudioAttributes attrToMatch, int rule)
throws IllegalArgumentException {
- if (!isValidSystemApiRule(rule)) {
+ if (!isValidAttributesSystemApiRule(rule)) {
throw new IllegalArgumentException("Illegal rule value " + rule);
}
- return addRuleInt(attrToMatch, rule);
+ return checkAddRuleObjInternal(rule, attrToMatch);
}
/**
@@ -186,104 +253,212 @@
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
* @return the same Builder instance.
* @throws IllegalArgumentException
+ * @see {@link #addRule(AudioAttributes, int)}
*/
@SystemApi
public Builder excludeRule(AudioAttributes attrToMatch, int rule)
throws IllegalArgumentException {
+ if (!isValidAttributesSystemApiRule(rule)) {
+ throw new IllegalArgumentException("Illegal rule value " + rule);
+ }
+ return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, attrToMatch);
+ }
+
+ /**
+ * Add a rule for the selection of which streams are mixed together.
+ * The rule defines what the matching will be made on. It also determines the type of the
+ * property to match against.
+ * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+ * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+ * {@link AudioMixingRule#RULE_MATCH_UID}.
+ * @param property see the definition of each rule for the type to use (either an
+ * {@link AudioAttributes} or an {@link java.lang.Integer}).
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ * @see {@link #excludeMixRule(int, Object)}
+ */
+ @SystemApi
+ public Builder addMixRule(int rule, Object property) throws IllegalArgumentException {
if (!isValidSystemApiRule(rule)) {
throw new IllegalArgumentException("Illegal rule value " + rule);
}
- return addRuleInt(attrToMatch, rule | RULE_EXCLUSION_MASK);
+ return checkAddRuleObjInternal(rule, property);
+ }
+
+ /**
+ * Add a rule by exclusion for the selection of which streams are mixed together.
+ * <br>For instance the following code
+ * <br><pre>
+ * AudioAttributes mediaAttr = new AudioAttributes.Builder()
+ * .setUsage(AudioAttributes.USAGE_MEDIA)
+ * .build();
+ * AudioMixingRule noMediaRule = new AudioMixingRule.Builder()
+ * .addMixRule(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, mediaAttr)
+ * .excludeMixRule(AudioMixingRule.RULE_MATCH_UID, new Integer(uidToExclude)
+ * .build();
+ * </pre>
+ * <br>will create a rule which maps to usage USAGE_MEDIA, but excludes any stream
+ * coming from the specified UID.
+ * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+ * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+ * {@link AudioMixingRule#RULE_MATCH_UID}.
+ * @param property see the definition of each rule for the type to use (either an
+ * {@link AudioAttributes} or an {@link java.lang.Integer}).
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ @SystemApi
+ public Builder excludeMixRule(int rule, Object property) throws IllegalArgumentException {
+ if (!isValidSystemApiRule(rule)) {
+ throw new IllegalArgumentException("Illegal rule value " + rule);
+ }
+ return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, property);
}
/**
* Add or exclude a rule for the selection of which streams are mixed together.
- * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
- * rule hasn't been set yet.
- * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
- * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
- * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
- * {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET}.
+ * Does error checking on the parameters.
+ * @param rule
+ * @param property
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
- Builder addRuleInt(AudioAttributes attrToMatch, int rule)
+ private Builder checkAddRuleObjInternal(int rule, Object property)
throws IllegalArgumentException {
- if (attrToMatch == null) {
- throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+ if (property == null) {
+ throw new IllegalArgumentException("Illegal null argument for mixing rule");
}
- if (!isValidIntRule(rule)) {
+ if (!isValidRule(rule)) {
throw new IllegalArgumentException("Illegal rule value " + rule);
- } else {
- // as rules are added to the Builder, we verify they are consistent with the type
- // of mix being built. When adding the first rule, the mix type is MIX_TYPE_INVALID.
- if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
- if (isPlayerRule(rule)) {
- mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
- } else {
- mTargetMixType = AudioMix.MIX_TYPE_RECORDERS;
- }
- } else if (((mTargetMixType == AudioMix.MIX_TYPE_PLAYERS) && !isPlayerRule(rule))
- || ((mTargetMixType == AudioMix.MIX_TYPE_RECORDERS) && isPlayerRule(rule)))
- {
- throw new IllegalArgumentException("Incompatible rule for mix");
+ }
+ final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+ if (isAudioAttributeRule(match_rule)) {
+ if (!(property instanceof AudioAttributes)) {
+ throw new IllegalArgumentException("Invalid AudioAttributes argument");
}
+ return addRuleInternal((AudioAttributes) property, null, rule);
+ } else {
+ // implies integer match rule
+ if (!(property instanceof Integer)) {
+ throw new IllegalArgumentException("Invalid Integer argument");
+ }
+ return addRuleInternal(null, (Integer) property, rule);
+ }
+ }
+
+ /**
+ * Add or exclude a rule on AudioAttributes or integer property for the selection of which
+ * streams are mixed together.
+ * No rule-to-parameter type check, all done in {@link #checkAddRuleObjInternal(int, Object)}.
+ * Exceptions are thrown only when incompatible rules are added.
+ * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
+ * rule hasn't been set yet, null if not used.
+ * @param intProp an integer property to match or exclude, null if not used.
+ * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
+ * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+ * {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+ * {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET},
+ * {@link AudioMixingRule#RULE_MATCH_UID}, {@link AudioMixingRule#RULE_EXCLUDE_UID}.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
+ throws IllegalArgumentException {
+ // as rules are added to the Builder, we verify they are consistent with the type
+ // of mix being built. When adding the first rule, the mix type is MIX_TYPE_INVALID.
+ if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
+ if (isPlayerRule(rule)) {
+ mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
+ } else {
+ mTargetMixType = AudioMix.MIX_TYPE_RECORDERS;
+ }
+ } else if (((mTargetMixType == AudioMix.MIX_TYPE_PLAYERS) && !isPlayerRule(rule))
+ || ((mTargetMixType == AudioMix.MIX_TYPE_RECORDERS) && isPlayerRule(rule)))
+ {
+ throw new IllegalArgumentException("Incompatible rule for mix");
}
synchronized (mCriteria) {
Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+ final int match_rule = rule & ~RULE_EXCLUSION_MASK;
while (crIterator.hasNext()) {
final AttributeMatchCriterion criterion = crIterator.next();
- if ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
- || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
- // "usage"-based rule
- if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
- if (criterion.mRule == rule) {
- // rule already exists, we're done
- return this;
- } else {
- // criterion already exists with a another rule, it is incompatible
- throw new IllegalArgumentException("Contradictory rule exists for "
- + attrToMatch);
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ // "usage"-based rule
+ if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
+ if (criterion.mRule == rule) {
+ // rule already exists, we're done
+ return this;
+ } else {
+ // criterion already exists with a another rule,
+ // it is incompatible
+ throw new IllegalArgumentException("Contradictory rule exists"
+ + " for " + attrToMatch);
+ }
}
- }
- } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
- || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
- // "capture preset"-base rule
- if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
- if (criterion.mRule == rule) {
- // rule already exists, we're done
- return this;
- } else {
- // criterion already exists with a another rule, it is incompatible
- throw new IllegalArgumentException("Contradictory rule exists for "
- + attrToMatch);
+ break;
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ // "capture preset"-base rule
+ if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
+ if (criterion.mRule == rule) {
+ // rule already exists, we're done
+ return this;
+ } else {
+ // criterion already exists with a another rule,
+ // it is incompatible
+ throw new IllegalArgumentException("Contradictory rule exists"
+ + " for " + attrToMatch);
+ }
}
- }
+ break;
+ case RULE_MATCH_UID:
+ // "usage"-based rule
+ if (criterion.mIntProp.intValue() == intProp.intValue()) {
+ if (criterion.mRule == rule) {
+ // rule already exists, we're done
+ return this;
+ } else {
+ // criterion already exists with a another rule,
+ // it is incompatible
+ throw new IllegalArgumentException("Contradictory rule exists"
+ + " for UID " + intProp);
+ }
+ }
+ break;
}
}
// rule didn't exist, add it
+ // FIXME doesn't work with RULE_MATCH_UID yet
mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
}
return this;
}
Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
- int rule = in.readInt();
- AudioAttributes attr;
- if ((rule == RULE_MATCH_ATTRIBUTE_USAGE) || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
- int usage = in.readInt();
- attr = new AudioAttributes.Builder()
- .setUsage(usage).build();
- } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
- || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
- int preset = in.readInt();
- attr = new AudioAttributes.Builder()
- .setInternalCapturePreset(preset).build();
- } else {
- in.readInt(); // assume there was in int value to read as for now they come in pair
- throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
+ final int rule = in.readInt();
+ final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+ AudioAttributes attr = null;
+ Integer intProp = null;
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ int usage = in.readInt();
+ attr = new AudioAttributes.Builder()
+ .setUsage(usage).build();
+ break;
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ int preset = in.readInt();
+ attr = new AudioAttributes.Builder()
+ .setInternalCapturePreset(preset).build();
+ break;
+ case RULE_MATCH_UID:
+ intProp = new Integer(in.readInt());
+ break;
+ default:
+ // assume there was in int value to read as for now they come in pair
+ in.readInt();
+ throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
}
- return addRuleInt(attr, rule);
+ return addRuleInternal(attr, intProp, rule);
}
/**
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 252f5f4..5ad6126 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -169,6 +169,14 @@
textDump += " match capture preset ";
textDump += criterion.mAttr.getCapturePreset();
break;
+ case AudioMixingRule.RULE_MATCH_UID:
+ textDump += " match UID ";
+ textDump += criterion.mIntProp.toString();
+ break;
+ case AudioMixingRule.RULE_EXCLUDE_UID:
+ textDump += " exclude UID ";
+ textDump += criterion.mIntProp.toString();
+ break;
default:
textDump += "invalid rule!";
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 869512d..93e6dac 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -473,8 +473,9 @@
// the service will be told when we connect.
if (mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // addSubscription instead of addSubscriptionWithOptions when the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects addSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(parentId, mServiceCallbacks);
} else {
@@ -500,9 +501,9 @@
// Tell the service if necessary.
if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // removeSubscription instead of removeSubscriptionWithOptions when the options
- // are null.
+ // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects removeSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
} else {
@@ -572,9 +573,9 @@
Subscription sub = subscriptionEntry.getValue();
for (Bundle options : sub.getOptionsList()) {
try {
- // NOTE: In order not to break the behavior of the support library,
- // call addSubscription instead of addSubscriptionWithOptions when
- // the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null.
+ // Otherwise, it will break the action of support library which expects
+ // addSubscription will be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(id, mServiceCallbacks);
} else {
@@ -1034,7 +1035,7 @@
* are the initial data as requested.
*/
@Override
- public void onConnect(final String root, final MediaSession.Token session,
+ public void onConnect(String root, MediaSession.Token session,
final Bundle extras) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
@@ -1054,7 +1055,12 @@
}
@Override
- public void onLoadChildren(final String parentId, final ParceledListSlice list,
+ public void onLoadChildren(String parentId, ParceledListSlice list) {
+ onLoadChildrenWithOptions(parentId, list, null);
+ }
+
+ @Override
+ public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
final Bundle options) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a56..3d9b60d 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -605,6 +605,7 @@
/**
* Request that the player start playback for a specific media id.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
@@ -626,6 +627,7 @@
* An empty or null query should be treated as a request to play any
* music.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param query The search query.
* @param extras Optional extras that can include extra information
* about the query.
@@ -646,6 +648,7 @@
/**
* Request that the player start playback for a specific {@link Uri}.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param uri The URI of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..8c5b19c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
+ * Set this flag on the session to indicate that it can handle
+ * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
+ */
+ public static final int FLAG_HANDLES_PREPARE_ONLY = 1 << 2;
+
+ /**
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
@@ -100,6 +106,7 @@
@IntDef(flag = true, value = {
FLAG_HANDLES_MEDIA_BUTTONS,
FLAG_HANDLES_TRANSPORT_CONTROLS,
+ FLAG_HANDLES_PREPARE_ONLY,
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index bbe04b5..1079a1f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,6 +133,21 @@
public static final long ACTION_PLAY_FROM_URI = 1 << 13;
/**
+ * Used as an optional boolean extra field in
+ * {@link MediaController.TransportControls#playFromMediaId},
+ * {@link MediaController.TransportControls#playFromSearch}, and
+ * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
+ * the default behavior of starting the playback after preparing. Check
+ * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+ *
+ * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
+ * @see MediaController.TransportControls#playFromMediaId
+ * @see MediaController.TransportControls#playFromSearch
+ * @see MediaController.TransportControls#playFromUri
+ */
+ public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+
+ /**
* 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.
*
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
new file mode 100644
index 0000000..707db06
--- /dev/null
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.io.PrintWriter;
+import java.util.UUID;
+
+/**
+ * A class that allows interaction with the actual sound trigger detection on the system.
+ * Sound trigger detection refers to a detectors that match generic sound patterns that are
+ * not voice-based. The voice-based recognition models should utilize the {@link
+ * VoiceInteractionService} instead. Access to this class is protected by a permission
+ * granted only to system or privileged apps.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoundTriggerDetector {
+ private static final boolean DBG = false;
+ private static final String TAG = "SoundTriggerDetector";
+
+ private final Object mLock = new Object();
+
+ private final ISoundTriggerService mSoundTriggerService;
+ private final UUID mSoundModelId;
+ private final Callback mCallback;
+ private final Handler mHandler;
+ private final RecognitionCallback mRecognitionCallback;
+
+ public abstract class Callback {
+ /**
+ * Called when the availability of the sound model changes.
+ */
+ public abstract void onAvailabilityChanged(int status);
+
+ /**
+ * Called when the sound model has triggered (such as when it matched a
+ * given sound pattern).
+ */
+ public abstract void onDetected();
+
+ /**
+ * Called when the detection fails due to an error.
+ */
+ public abstract void onError();
+
+ /**
+ * Called when the recognition is paused temporarily for some reason.
+ * This is an informational callback, and the clients shouldn't be doing anything here
+ * except showing an indication on their UI if they have to.
+ */
+ public abstract void onRecognitionPaused();
+
+ /**
+ * Called when the recognition is resumed after it was temporarily paused.
+ * This is an informational callback, and the clients shouldn't be doing anything here
+ * except showing an indication on their UI if they have to.
+ */
+ public abstract void onRecognitionResumed();
+ }
+
+ /**
+ * This class should be constructed by the {@link SoundTriggerManager}.
+ * @hide
+ */
+ SoundTriggerDetector(ISoundTriggerService soundTriggerService, UUID soundModelId,
+ @NonNull Callback callback, @Nullable Handler handler) {
+ mSoundTriggerService = soundTriggerService;
+ mSoundModelId = soundModelId;
+ mCallback = callback;
+ if (handler == null) {
+ mHandler = new Handler();
+ } else {
+ mHandler = handler;
+ }
+ mRecognitionCallback = new RecognitionCallback();
+ }
+
+ /**
+ * Starts recognition on the associated sound model. Result is indicated via the
+ * {@link Callback}.
+ * @return Indicates whether the call succeeded or not.
+ */
+ public boolean startRecognition() {
+ if (DBG) {
+ Slog.d(TAG, "startRecognition()");
+ }
+ try {
+ mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
+ mRecognitionCallback);
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Stops recognition for the associated model.
+ */
+ public boolean stopRecognition() {
+ try {
+ mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId),
+ mRecognitionCallback);
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ public void dump(String prefix, PrintWriter pw) {
+ synchronized (mLock) {
+ // TODO: Dump useful debug information.
+ }
+ }
+
+ /**
+ * Callback that handles events from the lower sound trigger layer.
+ * @hide
+ */
+ private static class RecognitionCallback extends
+ IRecognitionStatusCallback.Stub {
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onDetected(SoundTrigger.RecognitionEvent event) {
+ Slog.e(TAG, "onDetected()" + event);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onError(int status) {
+ Slog.e(TAG, "onError()" + status);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onRecognitionPaused() {
+ Slog.e(TAG, "onRecognitionPaused()");
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onRecognitionResumed() {
+ Slog.e(TAG, "onRecognitionResumed()");
+ }
+ }
+}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
new file mode 100644
index 0000000..4fd3310
--- /dev/null
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.HashMap;
+import java.util.UUID;
+
+/**
+ * This class provides management of non-voice (general sound trigger) based sound recognition
+ * models. Usage of this class is restricted to system or signature applications only. This allows
+ * OEMs to write apps that can manage non-voice based sound trigger models.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoundTriggerManager {
+ private static final boolean DBG = false;
+ private static final String TAG = "SoundTriggerManager";
+
+ private final Context mContext;
+ private final ISoundTriggerService mSoundTriggerService;
+
+ // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
+ // the createSoundTriggerDetector() call.
+ private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap;
+
+ /**
+ * @hide
+ */
+ public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService ) {
+ if (DBG) {
+ Slog.i(TAG, "SoundTriggerManager created.");
+ }
+ mSoundTriggerService = soundTriggerService;
+ mContext = context;
+ mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>();
+ }
+
+ /**
+ * Updates the given sound trigger model.
+ */
+ public void updateModel(Model model) {
+ try {
+ mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Returns the sound trigger model represented by the given UUID. An instance of {@link Model}
+ * is returned.
+ */
+ public Model getModel(UUID soundModelId) {
+ try {
+ return new Model(mSoundTriggerService.getSoundModel(
+ new ParcelUuid(soundModelId)));
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Deletes the sound model represented by the provided UUID.
+ */
+ public void deleteModel(UUID soundModelId) {
+ try {
+ mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Creates an instance of {@link SoundTriggerDetector} which can be used to start/stop
+ * recognition on the model and register for triggers from the model. Note that this call
+ * invalidates any previously returned instances for the same sound model Uuid.
+ *
+ * @param soundModelId UUID of the sound model to create the receiver object for.
+ * @param callback Instance of the {@link SoundTriggerDetector#Callback} object for the
+ * callbacks for the given sound model.
+ * @param handler The Handler to use for the callback operations. A null value will use the
+ * current thread's Looper.
+ * @return Instance of {@link SoundTriggerDetector} or null on error.
+ */
+ @Nullable
+ public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
+ @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
+ if (soundModelId == null) {
+ return null;
+ }
+
+ SoundTriggerDetector oldInstance = mReceiverInstanceMap.get(soundModelId);
+ if (oldInstance != null) {
+ // Shutdown old instance.
+ }
+ SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerService,
+ soundModelId, callback, handler);
+ mReceiverInstanceMap.put(soundModelId, newInstance);
+ return newInstance;
+ }
+
+ /**
+ * Class captures the data and fields that represent a non-keyphrase sound model. Use the
+ * factory constructor {@link Model#create()} to create an instance.
+ */
+ // We use encapsulation to expose the SoundTrigger.GenericSoundModel as a SystemApi. This
+ // prevents us from exposing SoundTrigger.GenericSoundModel as an Api.
+ public static class Model {
+
+ private SoundTrigger.GenericSoundModel mGenericSoundModel;
+
+ /**
+ * @hide
+ */
+ Model(SoundTrigger.GenericSoundModel soundTriggerModel) {
+ mGenericSoundModel = soundTriggerModel;
+ }
+
+ /**
+ * Factory constructor to create a SoundModel instance for use with methods in this
+ * class.
+ */
+ public static Model create(UUID modelUuid, UUID vendorUuid, byte[] data) {
+ return new Model(new SoundTrigger.GenericSoundModel(modelUuid,
+ vendorUuid, data));
+ }
+
+ public UUID getModelUuid() {
+ return mGenericSoundModel.uuid;
+ }
+
+ public UUID getVendorUuid() {
+ return mGenericSoundModel.vendorUuid;
+ }
+
+ public byte[] getModelData() {
+ return mGenericSoundModel.data;
+ }
+
+ /**
+ * @hide
+ */
+ SoundTrigger.GenericSoundModel getGenericSoundModel() {
+ return mGenericSoundModel;
+ }
+ }
+}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0febc16..d189333 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -41,6 +41,7 @@
interface ITvInputManager {
List<TvInputInfo> getTvInputList(int userId);
TvInputInfo getTvInputInfo(in String inputId, int userId);
+ void setTvInputInfo(in TvInputInfo inputInfo, int userId);
int getTvInputState(in String inputId, int userId);
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
diff --git a/media/java/android/media/tv/ITvInputManagerCallback.aidl b/media/java/android/media/tv/ITvInputManagerCallback.aidl
index 3bf415b..395c9f3 100644
--- a/media/java/android/media/tv/ITvInputManagerCallback.aidl
+++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl
@@ -29,5 +29,5 @@
void onInputStateChanged(in String inputId, int state);
- void onTvInputInfoChanged(in String inputId, in TvInputInfo TvInputInfo);
+ void onTvInputInfoChanged(in TvInputInfo TvInputInfo);
}
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index 9f13882..4fdc102 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -24,9 +24,7 @@
* @hide
*/
oneway interface ITvInputServiceCallback {
- void addHardwareTvInput(in int deviceId, in TvInputInfo inputInfo);
- void addHdmiTvInput(in int id, in TvInputInfo inputInfo);
- void removeTvInput(in String inputId);
-
- void setTvInputInfo(in String inputId, in TvInputInfo inputInfo);
+ void addHardwareInput(in int deviceId, in TvInputInfo inputInfo);
+ void addHdmiInput(in int id, in TvInputInfo inputInfo);
+ void removeHardwareInput(in String inputId);
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 671a86f..20491e4 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -107,15 +107,6 @@
*/
public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
- private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray();
-
- private static final String XML_START_TAG_NAME = "tv-input";
- private static final String DELIMITER_INFO_IN_ID = "/";
- private static final String PREFIX_HDMI_DEVICE = "HDMI";
- private static final String PREFIX_HARDWARE_DEVICE = "HW";
- private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4;
- private static final int LENGTH_HDMI_DEVICE_ID = 2;
-
private final ResolveInfo mService;
private final String mId;
private final String mParentId;
@@ -137,21 +128,6 @@
private Uri mIconUri;
private boolean mIsConnectedToHdmiSwitch;
- static {
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE,
- TYPE_OTHER);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE, TYPE_COMPOSITE);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT, TYPE_COMPONENT);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI);
- sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT,
- TYPE_DISPLAY_PORT);
- }
-
/**
* Create a new instance of the TvInputInfo class, instantiating it from the given Context,
* ResolveInfo, and HdmiDeviceInfo.
@@ -260,93 +236,6 @@
.build();
}
- static TvInputInfo createTvInputInfo(Context context, ResolveInfo resolveInfo, Icon icon,
- int labelResId, int tunerCount, boolean canRecord, HdmiDeviceInfo hdmiDeviceInfo,
- String parentId, TvInputHardwareInfo tvInputHardwareInfo)
- throws IOException, XmlPullParserException {
- ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name);
- String id;
- int type;
- boolean isHardwareInput = false;
- boolean isConnectedToHdmiSwitch = false;
-
- if (hdmiDeviceInfo != null) {
- id = generateInputIdForHdmiDevice(componentName, hdmiDeviceInfo);
- type = TYPE_HDMI;
- isHardwareInput = true;
- isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
- tunerCount = 0;
- } else if (tvInputHardwareInfo != null) {
- id = generateInputIdForHardware(componentName, tvInputHardwareInfo);
- type = sHardwareTypeToTvInputType.get(tvInputHardwareInfo.getType(), TYPE_TUNER);
- isHardwareInput = true;
- tunerCount = 0;
- } else {
- id = generateInputIdForComponentName(componentName);
- type = TYPE_TUNER;
- }
-
- TvInputInfo info = new TvInputInfo(resolveInfo, id, parentId, type, isHardwareInput,
- isConnectedToHdmiSwitch, tunerCount, canRecord);
- return parseServiceMetadata(context, resolveInfo, type, info);
- }
-
- private static TvInputInfo parseServiceMetadata(
- Context context, ResolveInfo service, int inputType, TvInputInfo input)
- throws XmlPullParserException, IOException {
- ServiceInfo si = service.serviceInfo;
- PackageManager pm = context.getPackageManager();
- XmlResourceParser parser = null;
- try {
- parser = si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA);
- if (parser == null) {
- throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA
- + " meta-data for " + si.name);
- }
-
- Resources res = pm.getResourcesForApplication(si.applicationInfo);
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- }
-
- String nodeName = parser.getName();
- if (!XML_START_TAG_NAME.equals(nodeName)) {
- throw new XmlPullParserException(
- "Meta-data does not start with tv-input-service tag in " + si.name);
- }
-
- TypedArray sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.TvInputService);
- input.mSetupActivity = sa.getString(
- com.android.internal.R.styleable.TvInputService_setupActivity);
- if (DEBUG) {
- Log.d(TAG, "Setup activity loaded. [" + input.mSetupActivity + "] for " + si.name);
- }
- if (inputType == TYPE_TUNER && TextUtils.isEmpty(input.mSetupActivity)) {
- throw new XmlPullParserException("Setup activity not found in " + si.name);
- }
- input.mSettingsActivity = sa.getString(
- com.android.internal.R.styleable.TvInputService_settingsActivity);
- if (DEBUG) {
- Log.d(TAG, "Settings activity loaded. [" + input.mSettingsActivity + "] for "
- + si.name);
- }
- sa.recycle();
-
- } catch (NameNotFoundException e) {
- throw new XmlPullParserException("Unable to create context for: " + si.packageName);
- } finally {
- if (parser != null) {
- parser.close();
- }
- }
- return input;
- }
-
/**
* Constructor.
*
@@ -645,46 +534,6 @@
return mService.serviceInfo.loadIcon(context.getPackageManager());
}
- /**
- * Used to generate an input id from a ComponentName.
- *
- * @param name the component name for generating an input id.
- * @return the generated input id for the given {@code name}.
- */
- private static String generateInputIdForComponentName(ComponentName name) {
- return name.flattenToShortString();
- }
-
- /**
- * Used to generate an input id from a ComponentName and HdmiDeviceInfo.
- *
- * @param name the component name for generating an input id.
- * @param deviceInfo HdmiDeviceInfo describing this TV input.
- * @return the generated input id for the given {@code name} and {@code deviceInfo}.
- */
- private static String generateInputIdForHdmiDevice(
- ComponentName name, HdmiDeviceInfo deviceInfo) {
- // Example of the format : "/HDMI%04X%02X"
- String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE
- + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X"
- + "%0" + LENGTH_HDMI_DEVICE_ID + "X";
- return name.flattenToShortString() + String.format(Locale.ENGLISH, format,
- deviceInfo.getPhysicalAddress(), deviceInfo.getId());
- }
-
- /**
- * Used to generate an input id from a ComponentName and TvInputHardwareInfo
- *
- * @param name the component name for generating an input id.
- * @param hardwareInfo TvInputHardwareInfo describing this TV input.
- * @return the generated input id for the given {@code name} and {@code hardwareInfo}.
- */
- private static String generateInputIdForHardware(
- ComponentName name, TvInputHardwareInfo hardwareInfo) {
- return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE
- + hardwareInfo.getDeviceId();
- }
-
public static final Parcelable.Creator<TvInputInfo> CREATOR =
new Parcelable.Creator<TvInputInfo>() {
@Override
@@ -720,6 +569,32 @@
* A convenience builder for creating {@link TvInputInfo} objects.
*/
public static final class Builder {
+ private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4;
+ private static final int LENGTH_HDMI_DEVICE_ID = 2;
+
+ private static final String XML_START_TAG_NAME = "tv-input";
+ private static final String DELIMITER_INFO_IN_ID = "/";
+ private static final String PREFIX_HDMI_DEVICE = "HDMI";
+ private static final String PREFIX_HARDWARE_DEVICE = "HW";
+
+ private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray();
+ static {
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE,
+ TYPE_OTHER);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE,
+ TYPE_COMPOSITE);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT,
+ TYPE_COMPONENT);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI);
+ sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT,
+ TYPE_DISPLAY_PORT);
+ }
+
private final Context mContext;
private final ResolveInfo mResolveInfo;
private Icon mIcon;
@@ -864,11 +739,102 @@
* @return TvInputInfo containing information about this TV input.
* @throws IOException If there was an I/O error.
* @throws XmlPullParserException If there was an XML parsing error.
- *
*/
public TvInputInfo build() throws IOException, XmlPullParserException {
- return createTvInputInfo(mContext, mResolveInfo, mIcon, mLabelResId, mTunerCount,
- mCanRecord, mHdmiDeviceInfo, mParentId, mTvInputHardwareInfo);
+ ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName,
+ mResolveInfo.serviceInfo.name);
+ String id;
+ int type;
+ boolean isHardwareInput = false;
+ boolean isConnectedToHdmiSwitch = false;
+
+ if (mHdmiDeviceInfo != null) {
+ id = generateInputId(componentName, mHdmiDeviceInfo);
+ type = TYPE_HDMI;
+ isHardwareInput = true;
+ isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+ mTunerCount = 0;
+ } else if (mTvInputHardwareInfo != null) {
+ id = generateInputId(componentName, mTvInputHardwareInfo);
+ type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
+ isHardwareInput = true;
+ mTunerCount = 0;
+ } else {
+ id = generateInputId(componentName);
+ type = TYPE_TUNER;
+ }
+
+ TvInputInfo info = new TvInputInfo(mResolveInfo, id, mParentId, type, isHardwareInput,
+ isConnectedToHdmiSwitch, mTunerCount, mCanRecord);
+ return parseServiceMetadata(type, info);
+ }
+
+ private static String generateInputId(ComponentName name) {
+ return name.flattenToShortString();
+ }
+
+ private static String generateInputId(ComponentName name, HdmiDeviceInfo hdmiDeviceInfo) {
+ // Example of the format : "/HDMI%04X%02X"
+ String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE
+ + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X"
+ + "%0" + LENGTH_HDMI_DEVICE_ID + "X";
+ return name.flattenToShortString() + String.format(Locale.ENGLISH, format,
+ hdmiDeviceInfo.getPhysicalAddress(), hdmiDeviceInfo.getId());
+ }
+
+ private static String generateInputId(ComponentName name,
+ TvInputHardwareInfo tvInputHardwareInfo) {
+ return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE
+ + tvInputHardwareInfo.getDeviceId();
+ }
+
+ private TvInputInfo parseServiceMetadata(int inputType, TvInputInfo info)
+ throws XmlPullParserException, IOException {
+ ServiceInfo si = mResolveInfo.serviceInfo;
+ PackageManager pm = mContext.getPackageManager();
+ try (XmlResourceParser parser =
+ si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA)) {
+ if (parser == null) {
+ throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA
+ + " meta-data for " + si.name);
+ }
+
+ Resources res = pm.getResourcesForApplication(si.applicationInfo);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!XML_START_TAG_NAME.equals(nodeName)) {
+ throw new XmlPullParserException(
+ "Meta-data does not start with tv-input-service tag in " + si.name);
+ }
+
+ TypedArray sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.TvInputService);
+ info.mSetupActivity = sa.getString(
+ com.android.internal.R.styleable.TvInputService_setupActivity);
+ if (DEBUG) {
+ Log.d(TAG, "Setup activity loaded. [" + info.mSetupActivity + "] for "
+ + si.name);
+ }
+ if (inputType == TYPE_TUNER && TextUtils.isEmpty(info.mSetupActivity)) {
+ throw new XmlPullParserException("Setup activity not found in " + si.name);
+ }
+ info.mSettingsActivity = sa.getString(
+ com.android.internal.R.styleable.TvInputService_settingsActivity);
+ if (DEBUG) {
+ Log.d(TAG, "Settings activity loaded. [" + info.mSettingsActivity + "] for "
+ + si.name);
+ }
+ sa.recycle();
+ } catch (NameNotFoundException e) {
+ throw new XmlPullParserException("Unable to create context for: " + si.packageName);
+ }
+ return info;
}
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f1de8fd..1cd1958 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -719,19 +719,16 @@
* the media on which a newer version of the package exists becomes available/unavailable.
*
* @param inputId The ID of the TV input.
- * @hide
*/
- @SystemApi
public void onInputUpdated(String inputId) {
}
/**
- * This is called when the information about a given TV input is changed.
+ * This is called when the information about a given TV input has been changed.
*
- * @param inputId The ID of the TV input.
* @param inputInfo TvInputInfo object that contains the information about the TV input.
*/
- public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+ public void onTvInputInfoChanged(TvInputInfo inputInfo) {
}
}
@@ -784,11 +781,11 @@
});
}
- public void postTvInputInfoChanged(final String inputId, final TvInputInfo inputInfo) {
+ public void postTvInputInfoChanged(final TvInputInfo inputInfo) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onTvInputInfoChanged(inputId, inputInfo);
+ mCallback.onTvInputInfoChanged(inputInfo);
}
});
}
@@ -1089,10 +1086,10 @@
}
@Override
- public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+ public void onTvInputInfoChanged(TvInputInfo inputInfo) {
synchronized (mLock) {
for (TvInputCallbackRecord record : mCallbackRecords) {
- record.postTvInputInfoChanged(inputId, inputInfo);
+ record.postTvInputInfoChanged(inputInfo);
}
}
}
@@ -1143,6 +1140,23 @@
}
/**
+ * Sets a new TvInputInfo object for a given input.
+ *
+ * <p>This is called internally only by {@link TvInputService}.
+ *
+ * @param inputInfo The TvInputInfo object to set.
+ * @throws IllegalArgumentException if the argument is {@code null}.
+ */
+ void setTvInputInfo(@NonNull TvInputInfo inputInfo) {
+ Preconditions.checkNotNull(inputInfo);
+ try {
+ mService.setTvInputInfo(inputInfo, mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Error trying to set " + inputInfo, e);
+ }
+ }
+
+ /**
* Returns the state of a given TV input.
*
* <p>The state is one of the following:
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index f74ae66..d48b2c8 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -150,25 +150,25 @@
@Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_INPUT,
deviceInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT,
deviceInfo).sendToTarget();
}
};
@@ -262,16 +262,16 @@
* <p>The system service automatically creates the TvInputInfo for each TV input based on
* information collected from the AndroidManifest.xml, thus it is not necessary to call this
* method unless the TV input has additional information to pass such as ability to record and
- * tuner count.
+ * tuner count. Attempting to change information about a TV input that the calling package does
+ * not own does nothing.
*
- * @param inputId The ID of the TV input.
+ * @param context The application context.
* @param inputInfo The TvInputInfo object that contains that new information.
*/
- public final void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = inputId;
- args.arg2 = inputInfo;
- mServiceHandler.obtainMessage(ServiceHandler.DO_SET_TV_INPUT_INFO, args).sendToTarget();
+ public static final void setTvInputInfo(Context context, TvInputInfo inputInfo) {
+ TvInputManager manager = (TvInputManager) context.getSystemService(
+ Context.TV_INPUT_SERVICE);
+ manager.setTvInputInfo(inputInfo);
}
private boolean isPassthroughInput(String inputId) {
@@ -525,7 +525,7 @@
public void notifyVideoUnavailable(final int reason) {
if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
|| reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
- throw new IllegalArgumentException("Unknown reason: " + reason);
+ Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason);
}
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -1934,55 +1934,42 @@
private static final int DO_CREATE_SESSION = 1;
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_CREATE_RECORDING_SESSION = 3;
- private static final int DO_ADD_HARDWARE_TV_INPUT = 4;
- private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5;
- private static final int DO_ADD_HDMI_TV_INPUT = 6;
- private static final int DO_REMOVE_HDMI_TV_INPUT = 7;
- private static final int DO_SET_TV_INPUT_INFO = 8;
+ private static final int DO_ADD_HARDWARE_INPUT = 4;
+ private static final int DO_REMOVE_HARDWARE_INPUT = 5;
+ private static final int DO_ADD_HDMI_INPUT = 6;
+ private static final int DO_REMOVE_HDMI_INPUT = 7;
- private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHardwareInput(deviceId, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHardwareTvInput", e);
+ Log.e(TAG, "error in broadcastAddHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastAddHdmiTvInput(int id, TvInputInfo inputInfo) {
+ private void broadcastAddHdmiInput(int id, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHdmiTvInput(id, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHdmiInput(id, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHdmiTvInput", e);
+ Log.e(TAG, "error in broadcastAddHdmiInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastRemoveTvInput(String inputId) {
+ private void broadcastRemoveHardwareInput(String inputId) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
+ mCallbacks.getBroadcastItem(i).removeHardwareInput(inputId);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastRemoveTvInput", e);
- }
- }
- mCallbacks.finishBroadcast();
- }
-
- private void broadcastSetTvInputInfo(String inputId, TvInputInfo inputInfo) {
- int n = mCallbacks.beginBroadcast();
- for (int i = 0; i < n; ++i) {
- try {
- mCallbacks.getBroadcastItem(i).setTvInputInfo(inputId, inputInfo);
- } catch (RemoteException e) {
- Log.e(TAG, "error in broadcastSetTvInputInfo", e);
+ Log.e(TAG, "error in broadcastRemoveHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
@@ -2088,48 +2075,38 @@
recordingSessionImpl.initialize(cb);
return;
}
- case DO_ADD_HARDWARE_TV_INPUT: {
+ case DO_ADD_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
TvInputInfo inputInfo = onHardwareAdded(hardwareInfo);
if (inputInfo != null) {
- broadcastAddHardwareTvInput(hardwareInfo.getDeviceId(), inputInfo);
+ broadcastAddHardwareInput(hardwareInfo.getDeviceId(), inputInfo);
}
return;
}
- case DO_REMOVE_HARDWARE_TV_INPUT: {
+ case DO_REMOVE_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
String inputId = onHardwareRemoved(hardwareInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
return;
}
- case DO_ADD_HDMI_TV_INPUT: {
+ case DO_ADD_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo);
if (inputInfo != null) {
- broadcastAddHdmiTvInput(deviceInfo.getId(), inputInfo);
+ broadcastAddHdmiInput(deviceInfo.getId(), inputInfo);
}
return;
}
- case DO_REMOVE_HDMI_TV_INPUT: {
+ case DO_REMOVE_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
String inputId = onHdmiDeviceRemoved(deviceInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
return;
}
- case DO_SET_TV_INPUT_INFO: {
- SomeArgs args = (SomeArgs) msg.obj;
- String inputId = (String) args.arg1;
- TvInputInfo inputInfo = (TvInputInfo) args.arg2;
- if (inputInfo != null) {
- broadcastSetTvInputInfo(inputId, inputInfo);
- }
- args.recycle();
- return;
- }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
return;
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 865e000..73f1e32 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -184,7 +184,7 @@
* Callback used to receive various status updates on the
* {@link android.media.tv.TvInputService.RecordingSession}
*/
- public class RecordingCallback {
+ public abstract static class RecordingCallback {
/**
* This is called when a recording session initiated by a call to
* {@link #connect(String, Uri)} has been established.
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index ef2cf2b..0dcc718 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -690,4 +690,6 @@
public static final int OPERATION_SET_OBJECT_REFERENCES = 0x9811;
/** Operation code for Skip */
public static final int OPERATION_SKIP = 0x9820;
+ /** Operation code for GetPartialObject64 */
+ public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 0x95C1;
}
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 4379a99..0e7013c 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -153,10 +153,11 @@
*
* @param objectHandle handle of the object to read
* @param objectSize the size of the object (this should match
- * {@link MtpObjectInfo#getCompressedSize}
+ * {@link MtpObjectInfo#getCompressedSize})
* @return the object's data, or null if reading fails
*/
public byte[] getObject(int objectHandle, int objectSize) {
+ Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
return native_get_object(objectHandle, objectSize);
}
@@ -179,6 +180,27 @@
}
/**
+ * Obtains object bytes in the specified range and writes it to an array.
+ * This call may block for an arbitrary amount of time depending on the size
+ * of the data and speed of the devices.
+ *
+ * This is a vender-extended operation supported by Android that enables us to pass
+ * unsigned 64-bit offset. Check if the MTP device supports the operation by using
+ * {@link MtpDeviceInfo#getOperationsSupported()}.
+ *
+ * @param objectHandle handle of the object to read
+ * @param offset Start index of reading range. It must be a non-negative value.
+ * @param size Size of reading range. It must be a non-negative value at most 0xffffffff.
+ * @param buffer Array to write data.
+ * @return Size of bytes that are actually read.
+ * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
+ */
+ public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer)
+ throws IOException {
+ return native_get_partial_object_64(objectHandle, offset, size, buffer);
+ }
+
+ /**
* Returns the thumbnail data for an object as a byte array.
* The size and format of the thumbnail data can be determined via
* {@link MtpObjectInfo#getThumbCompressedSize} and
@@ -284,7 +306,7 @@
* @param descriptor file descriptor to read the data from.
* @return true if the file transfer succeeds
*/
- public boolean sendObject(int objectHandle, int size, ParcelFileDescriptor descriptor) {
+ public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
return native_send_object(objectHandle, size, descriptor.getFd());
}
@@ -343,16 +365,18 @@
private native MtpStorageInfo native_get_storage_info(int storageId);
private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
private native MtpObjectInfo native_get_object_info(int objectHandle);
- private native byte[] native_get_object(int objectHandle, int objectSize);
+ private native byte[] native_get_object(int objectHandle, long objectSize);
private native long native_get_partial_object(
int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
+ private native int native_get_partial_object_64(
+ int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
private native byte[] native_get_thumbnail(int objectHandle);
private native boolean native_delete_object(int objectHandle);
- private native long native_get_parent(int objectHandle);
- private native long native_get_storage_id(int objectHandle);
+ private native int native_get_parent(int objectHandle);
+ private native int native_get_storage_id(int objectHandle);
private native boolean native_import_file(int objectHandle, String destPath);
private native boolean native_import_file(int objectHandle, int fd);
- private native boolean native_send_object(int objectHandle, int size, int fd);
+ private native boolean native_send_object(int objectHandle, long size, int fd);
private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
private native int native_submit_event_request();
private native MtpEvent native_reap_event_request(int handle);
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index 64aa997..02092b1 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -16,6 +16,8 @@
package android.mtp;
+import com.android.internal.util.Preconditions;
+
/**
* This class encapsulates information about an object on an MTP device.
* This corresponds to the ObjectInfo Dataset described in
@@ -96,10 +98,20 @@
* @return the object size
*/
public final int getCompressedSize() {
+ Preconditions.checkState(mCompressedSize >= 0);
return mCompressedSize;
}
/**
+ * Returns the size of the MTP object
+ *
+ * @return the object size
+ */
+ public final long getCompressedSizeLong() {
+ return uint32ToLong(mCompressedSize);
+ }
+
+ /**
* Returns the format code for the MTP object's thumbnail
* Will be zero for objects with no thumbnail
*
@@ -116,60 +128,126 @@
* @return the thumbnail size
*/
public final int getThumbCompressedSize() {
+ Preconditions.checkState(mThumbCompressedSize >= 0);
return mThumbCompressedSize;
}
/**
+ * Returns the size of the MTP object's thumbnail
+ * Will be zero for objects with no thumbnail
+ *
+ * @return the thumbnail size
+ */
+ public final long getThumbCompressedSizeLong() {
+ return uint32ToLong(mThumbCompressedSize);
+ }
+
+ /**
* Returns the width of the MTP object's thumbnail in pixels
* Will be zero for objects with no thumbnail
*
* @return the thumbnail width
*/
public final int getThumbPixWidth() {
+ Preconditions.checkState(mThumbPixWidth >= 0);
return mThumbPixWidth;
}
/**
+ * Returns the width of the MTP object's thumbnail in pixels
+ * Will be zero for objects with no thumbnail
+ *
+ * @return the thumbnail width
+ */
+ public final long getThumbPixWidthLong() {
+ return uint32ToLong(mThumbPixWidth);
+ }
+
+ /**
* Returns the height of the MTP object's thumbnail in pixels
* Will be zero for objects with no thumbnail
*
* @return the thumbnail height
*/
public final int getThumbPixHeight() {
+ Preconditions.checkState(mThumbPixHeight >= 0);
return mThumbPixHeight;
}
/**
+ * Returns the height of the MTP object's thumbnail in pixels
+ * Will be zero for objects with no thumbnail
+ *
+ * @return the thumbnail height
+ */
+ public final long getThumbPixHeightLong() {
+ return uint32ToLong(mThumbPixHeight);
+ }
+
+ /**
* Returns the width of the MTP object in pixels
* Will be zero for non-image objects
*
* @return the image width
*/
public final int getImagePixWidth() {
+ Preconditions.checkState(mImagePixWidth >= 0);
return mImagePixWidth;
}
/**
+ * Returns the width of the MTP object in pixels
+ * Will be zero for non-image objects
+ *
+ * @return the image width
+ */
+ public final long getImagePixWidthLong() {
+ return uint32ToLong(mImagePixWidth);
+ }
+
+ /**
* Returns the height of the MTP object in pixels
* Will be zero for non-image objects
*
* @return the image height
*/
public final int getImagePixHeight() {
+ Preconditions.checkState(mImagePixHeight >= 0);
return mImagePixHeight;
}
/**
+ * Returns the height of the MTP object in pixels
+ * Will be zero for non-image objects
+ *
+ * @return the image height
+ */
+ public final long getImagePixHeightLong() {
+ return uint32ToLong(mImagePixHeight);
+ }
+
+ /**
* Returns the depth of the MTP object in bits per pixel
* Will be zero for non-image objects
*
* @return the image depth
*/
public final int getImagePixDepth() {
+ Preconditions.checkState(mImagePixDepth >= 0);
return mImagePixDepth;
}
/**
+ * Returns the depth of the MTP object in bits per pixel
+ * Will be zero for non-image objects
+ *
+ * @return the image depth
+ */
+ public final long getImagePixDepthLong() {
+ return uint32ToLong(mImagePixDepth);
+ }
+
+ /**
* Returns the object handle for the object's parent
* Will be zero for the root directory of a storage unit
*
@@ -203,7 +281,7 @@
return mAssociationDesc;
}
- /**
+ /**
* Returns the sequence number for the MTP object
* This field is typically not used for MTP devices,
* but is sometimes used to define a sequence of photos
@@ -212,9 +290,22 @@
* @return the object's sequence number
*/
public final int getSequenceNumber() {
+ Preconditions.checkState(mSequenceNumber >= 0);
return mSequenceNumber;
}
+ /**
+ * Returns the sequence number for the MTP object
+ * This field is typically not used for MTP devices,
+ * but is sometimes used to define a sequence of photos
+ * on PTP cameras.
+ *
+ * @return the object's sequence number
+ */
+ public final long getSequenceNumberLong() {
+ return uint32ToLong(mSequenceNumber);
+ }
+
/**
* Returns the name of the MTP object
*
@@ -309,8 +400,8 @@
return this;
}
- public Builder setCompressedSize(int value) {
- mObjectInfo.mCompressedSize = value;
+ public Builder setCompressedSize(long value) {
+ mObjectInfo.mCompressedSize = longToUint32(value, "value");
return this;
}
@@ -329,18 +420,18 @@
return this;
}
- public Builder setImagePixDepth(int value) {
- mObjectInfo.mImagePixDepth = value;
+ public Builder setImagePixDepth(long value) {
+ mObjectInfo.mImagePixDepth = longToUint32(value, "value");
return this;
}
- public Builder setImagePixHeight(int value) {
- mObjectInfo.mImagePixHeight = value;
+ public Builder setImagePixHeight(long value) {
+ mObjectInfo.mImagePixHeight = longToUint32(value, "value");
return this;
}
- public Builder setImagePixWidth(int value) {
- mObjectInfo.mImagePixWidth = value;
+ public Builder setImagePixWidth(long value) {
+ mObjectInfo.mImagePixWidth = longToUint32(value, "value");
return this;
}
@@ -364,8 +455,8 @@
return this;
}
- public Builder setSequenceNumber(int value) {
- mObjectInfo.mSequenceNumber = value;
+ public Builder setSequenceNumber(long value) {
+ mObjectInfo.mSequenceNumber = longToUint32(value, "value");
return this;
}
@@ -374,8 +465,8 @@
return this;
}
- public Builder setThumbCompressedSize(int value) {
- mObjectInfo.mThumbCompressedSize = value;
+ public Builder setThumbCompressedSize(long value) {
+ mObjectInfo.mThumbCompressedSize = longToUint32(value, "value");
return this;
}
@@ -384,13 +475,13 @@
return this;
}
- public Builder setThumbPixHeight(int value) {
- mObjectInfo.mThumbPixHeight = value;
+ public Builder setThumbPixHeight(long value) {
+ mObjectInfo.mThumbPixHeight = longToUint32(value, "value");
return this;
}
- public Builder setThumbPixWidth(int value) {
- mObjectInfo.mThumbPixWidth = value;
+ public Builder setThumbPixWidth(long value) {
+ mObjectInfo.mThumbPixWidth = longToUint32(value, "value");
return this;
}
@@ -407,4 +498,13 @@
return result;
}
}
+
+ private static long uint32ToLong(int value) {
+ return value < 0 ? 0x100000000L + value : value;
+ }
+
+ private static int longToUint32(long value, String valueName) {
+ Preconditions.checkArgumentInRange(value, 0, 0xffffffffL, valueName);
+ return (int) value;
+ }
}
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index fe7ebfa..6ca5ac5 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -16,7 +16,7 @@
oneway interface IMediaBrowserService {
// Warning: DO NOT CHANGE the methods signature and order of methods.
- // The change of the order or the method signatures could break the support library.
+ // A change of the order or the method signatures could break the support library.
void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
void disconnect(IMediaBrowserServiceCallbacks callbacks);
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index dadb025..e6b0e8c 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -13,6 +13,10 @@
* @hide
*/
oneway interface IMediaBrowserServiceCallbacks {
+
+ // Warning: DO NOT CHANGE the methods signature and order of methods.
+ // A change of the order or the method signatures could break the support library.
+
/**
* Invoked when the connected has been established.
* @param root The root media id for browsing.
@@ -22,5 +26,6 @@
*/
void onConnect(String root, in MediaSession.Token session, in Bundle extras);
void onConnectFailed();
- void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
+ void onLoadChildren(String mediaId, in ParceledListSlice list);
+ void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6cf90d5..299b770 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -589,7 +589,14 @@
final ParceledListSlice<MediaBrowser.MediaItem> pls =
filteredList == null ? null : new ParceledListSlice<>(filteredList);
try {
- connection.callbacks.onLoadChildren(parentId, pls, options);
+ // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects onLoadChildren will
+ // be called when options are null.
+ if (options == null) {
+ connection.callbacks.onLoadChildren(parentId, pls);
+ } else {
+ connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
+ }
} catch (RemoteException ex) {
// The other side is in the process of crashing.
Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
index 42deab4..ba38569 100644
--- a/media/jni/android_media_ExifInterface.cpp
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -238,7 +238,7 @@
map.add(
String8("GPSTimeStamp"),
String8::format(
- "%2u:%2u:%2u",
+ "%02u:%02u:%02u",
image_data.gps.time_stamp[0].numerator
/ image_data.gps.time_stamp[0].denominator,
image_data.gps.time_stamp[1].numerator
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 025133f..3b892cb 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -150,4 +150,8 @@
mJavaObjStatus = UNKNOWN_ERROR;
}
+uint32_t JMediaDataSource::getFlags() {
+ return 0;
+}
+
} // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 2bc237e..34624eb 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -45,6 +45,7 @@
virtual ssize_t readAt(off64_t offset, size_t size);
virtual status_t getSize(off64_t* size);
virtual void close();
+ virtual uint32_t getFlags();
private:
// Protect all member variables with mLock because this object will be
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 5108eb5..c08a5e3 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -81,7 +81,8 @@
bool GetExifFromRawImage(
FileStream* stream, const String8& filename, piex::PreviewImageData& image_data) {
- memset(&image_data, 0, sizeof(image_data));
+ // Reset the PreviewImageData to its default.
+ image_data = piex::PreviewImageData();
if (!stream->exists()) {
// File is not exists.
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 8b7a926..0ecb750 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -26,6 +26,7 @@
#include <fcntl.h>
#include <memory>
+#include <string>
#include "jni.h"
#include "JNIHelp.h"
@@ -370,9 +371,26 @@
return info;
}
+bool check_uint32_arg(JNIEnv *env, const char* name, jlong value, uint32_t* out) {
+ if (value < 0 || 0xffffffff < value) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ (std::string("argument must be a 32-bit unsigned integer: ") + name).c_str());
+ return false;
+ }
+ *out = static_cast<uint32_t>(value);
+ return true;
+}
+
static jbyteArray
-android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
+android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jlong objectSizeLong)
{
+ uint32_t objectSize;
+ if (!check_uint32_arg(env, "objectSize", objectSizeLong, &objectSize)) {
+ return nullptr;
+ }
+
MtpDevice* device = get_device_from_object(env, thiz);
if (!device) {
return nullptr;
@@ -396,8 +414,8 @@
android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
jobject thiz,
jint objectID,
- jlong offset,
- jlong size,
+ jlong offsetLong,
+ jlong sizeLong,
jbyteArray array)
{
if (!array) {
@@ -405,19 +423,10 @@
return -1;
}
- if (offset < 0 || 0xffffffffL < offset) {
- jniThrowException(
- env,
- "java/lang/IllegalArgumentException",
- "Offset argument must be a 32-bit unsigned integer.");
- return -1;
- }
-
- if (size < 0 || 0xffffffffL < size) {
- jniThrowException(
- env,
- "java/lang/IllegalArgumentException",
- "Size argument must be a 32-bit unsigned integer.");
+ uint32_t offset;
+ uint32_t size;
+ if (!check_uint32_arg(env, "offset", offsetLong, &offset) ||
+ !check_uint32_arg(env, "size", sizeLong, &size)) {
return -1;
}
@@ -438,6 +447,60 @@
return static_cast<jlong>(written_size);
}
+static jint
+android_mtp_MtpDevice_get_partial_object_64(JNIEnv *env,
+ jobject thiz,
+ jint objectID,
+ jlong offset,
+ jlong size,
+ jbyteArray array) {
+ if (!array) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
+ return -1;
+ }
+
+ if (offset < 0) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "Offset argument must not be a negative value.");
+ return -1;
+ }
+
+ if (size < 0 || 0xffffffffL < size) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "Size argument must be a 32-bit unsigned integer.");
+ return -1;
+ }
+
+ MtpDevice* const device = get_device_from_object(env, thiz);
+ if (!device) {
+ jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
+ return -1;
+ }
+
+ const uint32_t native_object_handle = static_cast<uint32_t>(objectID);
+ const uint64_t native_offset = static_cast<uint64_t>(offset);
+ const uint32_t native_size = static_cast<uint32_t>(size);
+
+ JavaArrayWriter writer(env, array);
+ uint32_t written_size;
+ const bool success = device->readPartialObject64(
+ native_object_handle,
+ native_offset,
+ native_size,
+ &written_size,
+ JavaArrayWriter::writeTo,
+ &writer);
+ if (!success) {
+ jniThrowException(env, "java/io/IOException", "Failed to read data.");
+ return -1;
+ }
+ return static_cast<jint>(written_size);
+}
+
static jbyteArray
android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID)
{
@@ -467,22 +530,22 @@
}
}
-static jlong
+static jint
android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
{
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
- return (jlong)device->getParent(object_id);
+ return static_cast<jint>(device->getParent(object_id));
else
return -1;
}
-static jlong
+static jint
android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
{
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
- return (jlong)device->getStorageID(object_id);
+ return static_cast<jint>(device->getStorageID(object_id));
else
return -1;
}
@@ -516,8 +579,13 @@
}
static jboolean
-android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint size, jint fd)
+android_mtp_MtpDevice_send_object(
+ JNIEnv *env, jobject thiz, jint object_id, jlong sizeLong, jint fd)
{
+ uint32_t size;
+ if (!check_uint32_arg(env, "size", sizeLong, &size))
+ return JNI_FALSE;
+
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return JNI_FALSE;
@@ -647,16 +715,18 @@
(void *)android_mtp_MtpDevice_get_object_handles},
{"native_get_object_info", "(I)Landroid/mtp/MtpObjectInfo;",
(void *)android_mtp_MtpDevice_get_object_info},
- {"native_get_object", "(II)[B",(void *)android_mtp_MtpDevice_get_object},
+ {"native_get_object", "(IJ)[B",(void *)android_mtp_MtpDevice_get_object},
{"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
+ {"native_get_partial_object_64", "(IJJ[B)I",
+ (void *)android_mtp_MtpDevice_get_partial_object_64},
{"native_get_thumbnail", "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
{"native_delete_object", "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
- {"native_get_parent", "(I)J", (void *)android_mtp_MtpDevice_get_parent},
- {"native_get_storage_id", "(I)J", (void *)android_mtp_MtpDevice_get_storage_id},
+ {"native_get_parent", "(I)I", (void *)android_mtp_MtpDevice_get_parent},
+ {"native_get_storage_id", "(I)I", (void *)android_mtp_MtpDevice_get_storage_id},
{"native_import_file", "(ILjava/lang/String;)Z",
(void *)android_mtp_MtpDevice_import_file},
{"native_import_file", "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
- {"native_send_object", "(III)Z",(void *)android_mtp_MtpDevice_send_object},
+ {"native_send_object", "(IJI)Z",(void *)android_mtp_MtpDevice_send_object},
{"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
(void *)android_mtp_MtpDevice_send_object_info},
{"native_submit_event_request", "()I", (void *)android_mtp_MtpDevice_submit_event_request},
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index c3452d5..fa9ff01 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -54,8 +54,7 @@
android:name=".LauncherActivity"
android:theme="@android:style/Theme.NoDisplay"
android:icon="@drawable/ic_files_app"
- android:label="@string/files_label"
- android:enabled="@bool/productivity_device">
+ android:label="@string/files_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ff28e15..e8d8c8eb 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -18,7 +18,6 @@
<!-- Allow Advanced Devices default value to be customised -->
<bool name="config_defaultAdvancedDevices">false</bool>
- <bool name="productivity_device">true</bool>
<!-- Intentionally unset. Vendors should set this in an overlay. -->
<string name="trusted_quick_viewer_package"></string>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index ff7b7b9..afe9336 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -65,13 +65,9 @@
<string name="menu_paste_from_clipboard">Paste</string>
<!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
- <string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
- <!-- Menu item that reveals SD cards built into the device [CHAR LIMIT=24] -->
- <string name="menu_advanced_show" product="default">Show SD card</string>
+ <string name="menu_advanced_show">Show internal storage</string>
<!-- Menu item that hides internal storage built into the device [CHAR LIMIT=24] -->
- <string name="menu_advanced_hide" product="nosdcard">Hide internal storage</string>
- <!-- Menu item that hides SD cards built into the device [CHAR LIMIT=24] -->
- <string name="menu_advanced_hide" product="default">Hide SD card</string>
+ <string name="menu_advanced_hide">Hide internal storage</string>
<!-- Menu item that reveals the sizes of displayed files [CHAR LIMIT=24] -->
<string name="menu_file_size_show">Show file size</string>
@@ -185,6 +181,8 @@
<string name="copy_failure_alert_content">These files weren\'t copied: <xliff:g id="list">%1$s</xliff:g></string>
<!-- Contents of the moving failure alert dialog. [CHAR LIMIT=48] -->
<string name="move_failure_alert_content">These files weren\'t moved: <xliff:g id="list">%1$s</xliff:g></string>
+ <!-- Contents of the copying warning dialog due to converted files. [CHAR LIMIT=64] -->
+ <string name="copy_converted_warning_content">These files were converted to another format: <xliff:g id="list" example="Document.pdf, Photo.jpg, Song.ogg">%1$s</xliff:g></string>
<!-- Toast shown when a user copies files to clipboard. -->
<plurals name="clipboard_files_clipped">
<item quantity="one">Copied <xliff:g id="count" example="1">%1$d</xliff:g> file to clipboard.</item>
@@ -196,6 +194,9 @@
<string name="menu_rename">Rename</string>
<!-- Toast shown when renaming document failed with an error [CHAR LIMIT=48] -->
<string name="rename_error">Failed to rename document</string>
+ <!-- First line for notifications saying that some files were converted to a different format
+ during a copy. [CHAR LIMIT=48] -->
+ <string name="notification_copy_files_converted_title">Some files were converted</string>
<!-- DO NOT TRANSLATE - final phrase has not been decided yet (b/26750152) -->
<string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index ad8b0d1..ea7054f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -17,11 +17,13 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_UP;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.Fragment;
@@ -51,8 +53,8 @@
import android.widget.TextView;
import com.android.documentsui.RecentsProvider.ResumeColumns;
-import com.android.documentsui.SearchManager;
import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -102,7 +104,6 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
mState = (icicle != null)
? icicle.<State>getParcelable(EXTRA_STATE)
: buildState();
@@ -204,6 +205,8 @@
void onStackRestored(boolean restored, boolean external) {}
void onRootPicked(RootInfo root) {
+ mState.derivedMode = LocalPreferences.getViewMode(this, root, MODE_GRID);
+
// Clear entire backstack and start in new root
mState.onRootChanged(root);
mSearchManager.update(root);
@@ -260,11 +263,11 @@
return true;
case R.id.menu_grid:
- setUserMode(State.MODE_GRID);
+ setViewMode(State.MODE_GRID);
return true;
case R.id.menu_list:
- setUserMode(State.MODE_LIST);
+ setViewMode(State.MODE_LIST);
return true;
case R.id.menu_paste_from_clipboard:
@@ -419,24 +422,27 @@
invalidateOptionsMenu();
}
- public void onStateChanged() {
- invalidateOptionsMenu();
- }
-
/**
* Set state sort order based on explicit user action.
*/
void setUserSortOrder(int sortOrder) {
mState.userSortOrder = sortOrder;
- DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+ DirectoryFragment.get(getFragmentManager()).onSortOrderChanged();
}
/**
- * Set state mode based on explicit user action.
+ * Set mode based on explicit user action.
*/
- void setUserMode(int mode) {
- mState.userMode = mode;
- DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+ void setViewMode(@ViewMode int mode) {
+ checkState(mState.stack.root != null);
+ LocalPreferences.setViewMode(this, mState.stack.root, mode);
+ mState.derivedMode = mode;
+
+ // view icon needs to be updated, but we *could* do it
+ // in onOptionsItemSelected, and not do the full invalidation
+ // But! That's a larger refactoring we'll save for another day.
+ invalidateOptionsMenu();
+ DirectoryFragment.get(getFragmentManager()).onViewModeChanged();
}
public void setPending(boolean pending) {
@@ -485,6 +491,10 @@
return;
}
+ if (DirectoryFragment.get(getFragmentManager()).onBackPressed()) {
+ return;
+ }
+
if (!mState.hasLocationChanged()) {
super.onBackPressed();
return;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 6719b23..b0542b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,11 +16,11 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
@@ -35,7 +35,6 @@
import android.provider.DocumentsContract.Document;
import android.util.Log;
-import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
@@ -52,10 +51,10 @@
private final int mType;
private final RootInfo mRoot;
- private DocumentInfo mDoc;
private final Uri mUri;
private final int mUserSortOrder;
+ private DocumentInfo mDoc;
private CancellationSignal mSignal;
private DirectoryResult mResult;
@@ -64,9 +63,9 @@
super(context, ProviderExecutor.forAuthority(root.authority));
mType = type;
mRoot = root;
- mDoc = doc;
mUri = uri;
mUserSortOrder = userSortOrder;
+ mDoc = doc;
}
@Override
@@ -83,8 +82,6 @@
final DirectoryResult result = new DirectoryResult();
- int userMode = State.MODE_UNKNOWN;
-
// Use default document when searching
if (mType == DirectoryFragment.TYPE_SEARCH) {
final Uri docUri = DocumentsContract.buildDocumentUri(
@@ -98,25 +95,6 @@
}
}
- // Pick up any custom modes requested by user
- Cursor cursor = null;
- try {
- final Uri stateUri = RecentsProvider.buildState(
- mRoot.authority, mRoot.rootId, mDoc.documentId);
- cursor = resolver.query(stateUri, null, null, null, null);
- if (cursor.moveToFirst()) {
- userMode = getCursorInt(cursor, StateColumns.MODE);
- }
- } finally {
- IoUtils.closeQuietly(cursor);
- }
-
- if (userMode != State.MODE_UNKNOWN) {
- result.mode = userMode;
- } else {
- result.mode = State.MODE_GRID;
- }
-
if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
result.sortOrder = mUserSortOrder;
} else {
@@ -132,13 +110,13 @@
result.sortOrder = State.SORT_ORDER_UNKNOWN;
}
- Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
- + result.mode + ", sortOrder=" + result.sortOrder);
+ if (DEBUG)
+ Log.d(TAG, "userSortOrder=" + mUserSortOrder + ", sortOrder=" + result.sortOrder);
ContentProviderClient client = null;
+ Cursor cursor = null;
try {
client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
-
cursor = client.query(
mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
if (cursor == null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
index e7e4f73..22e438a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
@@ -29,7 +29,6 @@
public Cursor cursor;
public Exception exception;
- public int mode = MODE_UNKNOWN;
public int sortOrder = SORT_ORDER_UNKNOWN;
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 6dcd472..c3395ae 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -346,11 +346,13 @@
} else {
DirectoryFragment.showRecentsOpen(fm, anim);
- // Start recents in grid when requesting visual things
- final boolean visualMimes = MimePredicate.mimeMatches(
+ // In recents we pick layout mode based on the mimetype,
+ // picking GRID for visual types. We intentionally don't
+ // consult a user's saved preferences here since they are
+ // set per root (not per root and per mimetype).
+ boolean visualMimes = MimePredicate.mimeMatches(
MimePredicate.VISUAL_MIMES, mState.acceptMimes);
- mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
- mState.derivedMode = mState.userMode;
+ mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
}
} else {
if (mSearchManager.isSearching()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
deleted file mode 100644
index b8ef5ac..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.internal.util.Preconditions.checkArgument;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.text.Html;
-
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.services.FileOperationService;
-import com.android.documentsui.services.FileOperations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Alert dialog for failed operations.
- */
-public class FailureDialogFragment extends DialogFragment {
- private static final String TAG = "FailureDialogFragment";
-
- public static void show(FragmentManager fm, int failure,
- ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, int operationType) {
- // TODO: Add support for other failures than copy.
- if (failure != FileOperationService.FAILURE_COPY) {
- return;
- }
-
- final Bundle args = new Bundle();
- args.putInt(FileOperationService.EXTRA_FAILURE, failure);
- args.putInt(FileOperationService.EXTRA_OPERATION, operationType);
- args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList);
-
- final FragmentTransaction ft = fm.beginTransaction();
- final FailureDialogFragment fragment = new FailureDialogFragment();
- fragment.setArguments(args);
-
- ft.add(fragment, TAG);
- ft.commitAllowingStateLoss();
- }
-
- @Override
- public Dialog onCreateDialog(Bundle inState) {
- super.onCreate(inState);
-
- final int operationType = getArguments().getInt(FileOperationService.EXTRA_OPERATION);
- final List<DocumentInfo> failedSrcList = getArguments().getParcelableArrayList(
- FileOperationService.EXTRA_SRC_LIST);
-
- final StringBuilder list = new StringBuilder("<p>");
- for (DocumentInfo documentInfo : failedSrcList) {
- list.append(String.format("• %s<br>", documentInfo.displayName));
- }
- list.append("</p>");
-
- // TODO: Add support for other file operations.
- checkArgument(
- operationType == FileOperationService.OPERATION_COPY
- || operationType == FileOperationService.OPERATION_MOVE);
-
- int messageId = operationType == FileOperationService.OPERATION_COPY
- ? R.string.copy_failure_alert_content
- : R.string.move_failure_alert_content;
-
- final String messageFormat = getString(
- messageId);
-
- final String message = String.format(messageFormat, list.toString());
-
- return new AlertDialog.Builder(getActivity())
- .setMessage(Html.fromHtml(message))
- .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- })
- .create();
- }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 5abe7f6..f51f689 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -43,6 +44,7 @@
import android.widget.Spinner;
import android.widget.Toolbar;
+import com.android.documentsui.OperationDialogFragment.DialogType;
import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
@@ -121,20 +123,20 @@
ProviderExecutor.forAuthority(homeUri.getAuthority()));
}
- final int failure = intent.getIntExtra(FileOperationService.EXTRA_FAILURE, 0);
- final int opType = intent.getIntExtra(
- FileOperationService.EXTRA_OPERATION,
- FileOperationService.OPERATION_COPY);
-
+ final @DialogType int dialogType = intent.getIntExtra(
+ FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN);
// DialogFragment takes care of restoring the dialog on configuration change.
// Only show it manually for the first time (icicle is null).
- if (icicle == null && failure != 0) {
- final ArrayList<DocumentInfo> failedSrcList =
+ if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) {
+ final int opType = intent.getIntExtra(
+ FileOperationService.EXTRA_OPERATION,
+ FileOperationService.OPERATION_COPY);
+ final ArrayList<DocumentInfo> srcList =
intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST);
- FailureDialogFragment.show(
+ OperationDialogFragment.show(
getFragmentManager(),
- failure,
- failedSrcList,
+ dialogType,
+ srcList,
mState.stack,
opType);
}
@@ -254,9 +256,6 @@
pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
- newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- newWindow.setVisible(mProductivityDevice);
-
Menus.disableHiddenItems(menu, pasteFromCb);
return true;
}
@@ -285,6 +284,14 @@
Metrics.logMultiWindow(this);
Intent intent = LauncherActivity.createLaunchIntent(this);
intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
+
+ // With new multi-window mode we have to pick how we are launched.
+ // By default we'd be launched in-place above the existing app.
+ // By setting launch-to-side ActivityManager will open us to side.
+ if (inMultiWindowMode()) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE);
+ }
+
startActivity(intent);
}
@@ -296,12 +303,6 @@
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
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
index b3d0cf3..7930c28 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -74,6 +74,9 @@
private void startTask() {
Intent intent = createLaunchIntent(this);
+
+ // Forward any flags from the original intent.
+ intent.setFlags(getIntent().getFlags());
if (DEBUG) Log.d(TAG, "Starting new task > " + intent.getData());
startActivity(intent);
}
@@ -84,7 +87,7 @@
startActivity(intent);
}
- static Intent createLaunchIntent(Context context) {
+ static final Intent createLaunchIntent(Context context) {
Intent intent = new Intent(context, FilesActivity.class);
intent.setData(buildLaunchUri());
return intent;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 113e9d7..4bffc49 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -16,12 +16,19 @@
package com.android.documentsui;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.content.Context;
import android.preference.PreferenceManager;
+import com.android.documentsui.State.ViewMode;
+import com.android.documentsui.model.RootInfo;
+
public class LocalPreferences {
private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
private static final String KEY_FILE_SIZE = "fileSize";
+ private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
public static boolean getDisplayAdvancedDevices(Context context) {
boolean defaultAdvanced = context.getResources()
@@ -35,6 +42,12 @@
.getBoolean(KEY_FILE_SIZE, false);
}
+ public static @ViewMode int getViewMode(
+ Context context, RootInfo root, @ViewMode int fallback) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getInt(createKey(root), fallback);
+ }
+
public static void setDisplayAdvancedDevices(Context context, boolean display) {
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putBoolean(KEY_ADVANCED_DEVICES, display).apply();
@@ -44,4 +57,14 @@
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putBoolean(KEY_FILE_SIZE, display).apply();
}
+
+ public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
+ checkArgument(viewMode != MODE_UNKNOWN);
+ PreferenceManager.getDefaultSharedPreferences(context).edit()
+ .putInt(createKey(root), viewMode).apply();
+ }
+
+ private static String createKey(RootInfo root) {
+ return ROOT_VIEW_MODE_PREFIX + root.authority + root.rootId;
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index eb90b75..bae334b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -17,7 +17,10 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.internal.util.Preconditions.checkArgument;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
@@ -25,9 +28,16 @@
import android.provider.DocumentsContract;
import android.util.Log;
+import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperationService.OpType;
import com.android.internal.logging.MetricsLogger;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
/** @hide */
public final class Metrics {
private static final String TAG = "Metrics";
@@ -37,6 +47,7 @@
private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
private static final String AUTHORITY_STORAGE = "com.android.externalstorage.documents";
private static final String AUTHORITY_DOWNLOADS = "com.android.providers.downloads.documents";
+ private static final String AUTHORITY_MTP = "com.android.mtp.documents";
// These strings have to be whitelisted in tron. Do not change them.
private static final String COUNT_LAUNCH_ACTION = "docsui_launch_action";
@@ -47,11 +58,16 @@
private static final String COUNT_BROWSE_ROOT = "docsui_browse_root";
private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
+ private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system";
+ private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
+ private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
// #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
// (see below).
+ // Do not change or rearrange these values, that will break historical data. Only add to the end
+ // of the list.
private static final int ROOT_NONE = 0;
private static final int ROOT_OTHER = 1;
private static final int ROOT_AUDIO = 2;
@@ -61,10 +77,27 @@
private static final int ROOT_IMAGES = 6;
private static final int ROOT_RECENTS = 7;
private static final int ROOT_VIDEOS = 8;
+ private static final int ROOT_MTP = 9;
// Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
// are logged analogously to roots. Use negative numbers to identify apps.
private static final int ROOT_THIRD_PARTY_APP = -1;
+ @IntDef(flag = true, value = {
+ ROOT_NONE,
+ ROOT_OTHER,
+ ROOT_AUDIO,
+ ROOT_DEVICE_STORAGE,
+ ROOT_DOWNLOADS,
+ ROOT_HOME,
+ ROOT_IMAGES,
+ ROOT_RECENTS,
+ ROOT_VIDEOS,
+ ROOT_MTP,
+ ROOT_THIRD_PARTY_APP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Root {}
+
// Indices for bucketing mime types.
private static final int MIME_OTHER = -2; // anything not enumerated below
private static final int MIME_NONE = -1; // null mime
@@ -77,6 +110,66 @@
private static final int MIME_TEXT = 6; // text/*
private static final int MIME_VIDEO = 7; // video/*
+ @IntDef(flag = true, value = {
+ MIME_OTHER,
+ MIME_NONE,
+ MIME_ANY,
+ MIME_APPLICATION,
+ MIME_AUDIO,
+ MIME_IMAGE,
+ MIME_MESSAGE,
+ MIME_MULTIPART,
+ MIME_TEXT,
+ MIME_VIDEO
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Mime {}
+
+ // Codes representing different kinds of file operations. These are used for bucketing
+ // operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms.
+ private static final int FILEOP_OTHER = 0; // any file operation not listed below
+ private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider
+ private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider.
+ private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider.
+ private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider.
+ private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider.
+ private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider.
+ private static final int FILEOP_DELETE = 7;
+ private static final int FILEOP_OTHER_ERROR = -1;
+ private static final int FILEOP_COPY_ERROR = -2;
+ private static final int FILEOP_MOVE_ERROR = -3;
+ private static final int FILEOP_DELETE_ERROR = -4;
+
+ @IntDef(flag = true, value = {
+ FILEOP_OTHER,
+ FILEOP_COPY_INTRA_PROVIDER,
+ FILEOP_COPY_SYSTEM_PROVIDER,
+ FILEOP_COPY_EXTERNAL_PROVIDER,
+ FILEOP_MOVE_INTRA_PROVIDER,
+ FILEOP_MOVE_SYSTEM_PROVIDER,
+ FILEOP_MOVE_EXTERNAL_PROVIDER,
+ FILEOP_DELETE,
+ FILEOP_OTHER_ERROR,
+ FILEOP_COPY_ERROR,
+ FILEOP_MOVE_ERROR,
+ FILEOP_DELETE_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FileOp {}
+
+ // Codes representing different provider types. Used for sorting file operations when logging.
+ private static final int PROVIDER_INTRA = 0;
+ private static final int PROVIDER_SYSTEM = 1;
+ private static final int PROVIDER_EXTERNAL = 2;
+
+ @IntDef(flag = true, value = {
+ PROVIDER_INTRA,
+ PROVIDER_SYSTEM,
+ PROVIDER_EXTERNAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Provider {}
+
/**
* Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
*
@@ -140,6 +233,99 @@
}
/**
+ * Logs file operation stats. Call this when a file operation has completed. The given
+ * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
+ * provider to another vs copying within a given provider). No PII is logged.
+ *
+ * @param context
+ * @param operationType
+ * @param srcs
+ * @param dst
+ */
+ public static void logFileOperation(
+ Context context,
+ @OpType int operationType,
+ List<DocumentInfo> srcs,
+ @Nullable DocumentInfo dst) {
+ ProviderCounts counts = countProviders(srcs, dst);
+
+ if (counts.intraProvider > 0) {
+ logIntraProviderFileOps(context, dst.authority, operationType);
+ }
+ if (counts.systemProvider > 0) {
+ // Log file operations on system providers.
+ logInterProviderFileOps(context, COUNT_FILEOP_SYSTEM, dst, operationType);
+ }
+ if (counts.externalProvider > 0) {
+ // Log file operations on external providers.
+ logInterProviderFileOps(context, COUNT_FILEOP_EXTERNAL, dst, operationType);
+ }
+ }
+
+ /**
+ * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
+ * fails.
+ *
+ * @param context
+ * @param operationType
+ * @param failedFiles
+ */
+ public static void logFileOperationErrors(Context context, @OpType int operationType,
+ List<DocumentInfo> failedFiles) {
+ ProviderCounts counts = countProviders(failedFiles, null);
+
+ @FileOp int opCode = FILEOP_OTHER_ERROR;
+ switch (operationType) {
+ case FileOperationService.OPERATION_COPY:
+ opCode = FILEOP_COPY_ERROR;
+ break;
+ case FileOperationService.OPERATION_DELETE:
+ opCode = FILEOP_DELETE_ERROR;
+ break;
+ case FileOperationService.OPERATION_MOVE:
+ opCode = FILEOP_MOVE_ERROR;
+ break;
+ }
+ if (counts.systemProvider > 0) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, opCode);
+ }
+ if (counts.externalProvider > 0) {
+ logHistogram(context, COUNT_FILEOP_EXTERNAL, opCode);
+ }
+ }
+
+ /**
+ * Log the cancellation of a file operation. Call this when a Job is canceled.
+ * @param context
+ * @param operationType
+ */
+ public static void logFileOperationCancelled(Context context, @OpType int operationType) {
+ logHistogram(context, COUNT_FILEOP_CANCELED, operationType);
+ }
+
+ private static void logInterProviderFileOps(
+ Context context,
+ String histogram,
+ DocumentInfo dst,
+ @OpType int operationType) {
+ if (operationType == FileOperationService.OPERATION_DELETE) {
+ logHistogram(context, histogram, FILEOP_DELETE);
+ } else {
+ checkArgument(dst != null);
+ @Provider int providerType =
+ isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
+ logHistogram(context, histogram, getOpCode(operationType, providerType));
+ }
+ }
+
+ private static void logIntraProviderFileOps(
+ Context context, String authority, @OpType int operationType) {
+ // Find the right histogram to log to, then log the operation.
+ String histogram = isSystemProvider(authority) ? COUNT_FILEOP_SYSTEM : COUNT_FILEOP_EXTERNAL;
+ logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
+ }
+
+ /**
* Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
*
* @param context
@@ -167,7 +353,7 @@
* small set of hard-coded roots (ones provided by the system). Other roots are all grouped into
* a single ROOT_OTHER bucket.
*/
- private static int sanitizeRoot(Uri uri) {
+ private static @Root int sanitizeRoot(Uri uri) {
if (LauncherActivity.isLaunchUri(uri)) {
return ROOT_NONE;
}
@@ -192,13 +378,15 @@
}
case AUTHORITY_DOWNLOADS:
return ROOT_DOWNLOADS;
+ case AUTHORITY_MTP:
+ return ROOT_MTP;
default:
return ROOT_OTHER;
}
}
/** @see #sanitizeRoot(Uri) */
- private static int sanitizeRoot(RootInfo root) {
+ private static @Root int sanitizeRoot(RootInfo root) {
if (root.isRecents()) {
// Recents root is special and only identifiable via this method call. Other roots are
// identified by URI.
@@ -209,7 +397,7 @@
}
/** @see #sanitizeRoot(Uri) */
- private static int sanitizeRoot(ResolveInfo info) {
+ private static @Root int sanitizeRoot(ResolveInfo info) {
// Log all apps under a single bucket in the roots histogram.
return ROOT_THIRD_PARTY_APP;
}
@@ -221,7 +409,7 @@
* @param mimeType
* @return
*/
- private static int sanitizeMime(String mimeType) {
+ private static @Mime int sanitizeMime(String mimeType) {
if (mimeType == null) {
return MIME_NONE;
} else if ("*/*".equals(mimeType)) {
@@ -248,4 +436,75 @@
// Bucket all other types into one bucket.
return MIME_OTHER;
}
+
+ private static boolean isSystemProvider(String authority) {
+ switch (authority) {
+ case AUTHORITY_MEDIA:
+ case AUTHORITY_STORAGE:
+ case AUTHORITY_DOWNLOADS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @param operation
+ * @param providerType
+ * @return An opcode, suitable for use as histogram bucket, for the given operation/provider
+ * combination.
+ */
+ private static @FileOp int getOpCode(@OpType int operation, @Provider int providerType) {
+ switch (operation) {
+ case FileOperationService.OPERATION_COPY:
+ switch (providerType) {
+ case PROVIDER_INTRA:
+ return FILEOP_COPY_INTRA_PROVIDER;
+ case PROVIDER_SYSTEM:
+ return FILEOP_COPY_SYSTEM_PROVIDER;
+ case PROVIDER_EXTERNAL:
+ return FILEOP_COPY_EXTERNAL_PROVIDER;
+ }
+ case FileOperationService.OPERATION_MOVE:
+ switch (providerType) {
+ case PROVIDER_INTRA:
+ return FILEOP_MOVE_INTRA_PROVIDER;
+ case PROVIDER_SYSTEM:
+ return FILEOP_MOVE_SYSTEM_PROVIDER;
+ case PROVIDER_EXTERNAL:
+ return FILEOP_MOVE_EXTERNAL_PROVIDER;
+ }
+ case FileOperationService.OPERATION_DELETE:
+ return FILEOP_DELETE;
+ default:
+ Log.w(TAG, "Unrecognized operation type when logging a file operation");
+ return FILEOP_OTHER;
+ }
+ }
+
+ /**
+ * Count the given src documents and provide a tally of how many come from the same provider as
+ * the dst document (if a dst is provided), how many come from system providers, and how many
+ * come from external 3rd-party providers.
+ */
+ private static ProviderCounts countProviders(
+ List<DocumentInfo> srcs, @Nullable DocumentInfo dst) {
+ ProviderCounts counts = new ProviderCounts();
+ for (DocumentInfo doc: srcs) {
+ if (dst != null && doc.authority.equals(dst.authority)) {
+ counts.intraProvider++;
+ } else if (isSystemProvider(doc.authority)){
+ counts.systemProvider++;
+ } else {
+ counts.externalProvider++;
+ }
+ }
+ return counts;
+ }
+
+ private static class ProviderCounts {
+ int intraProvider;
+ int systemProvider;
+ int externalProvider;
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
new file mode 100644
index 0000000..85cc12b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.services.FileOperationService.OpType;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.IntDef;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.Html;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperations;
+import com.android.documentsui.services.Job;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Alert dialog for operation dialogs.
+ */
+public class OperationDialogFragment extends DialogFragment {
+
+ public static final int DIALOG_TYPE_UNKNOWN = 0;
+ public static final int DIALOG_TYPE_FAILURE = 1;
+ public static final int DIALOG_TYPE_CONVERTED = 2;
+
+ @IntDef(flag = true, value = {
+ DIALOG_TYPE_UNKNOWN,
+ DIALOG_TYPE_FAILURE,
+ DIALOG_TYPE_CONVERTED
+ })
+
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DialogType {}
+
+ private static final String TAG = "OperationDialogFragment";
+
+ public static void show(FragmentManager fm, @DialogType int dialogType,
+ ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack,
+ @OpType int operationType) {
+ final Bundle args = new Bundle();
+ args.putInt(FileOperationService.EXTRA_DIALOG_TYPE, dialogType);
+ args.putInt(FileOperationService.EXTRA_OPERATION, operationType);
+ args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList);
+
+ final FragmentTransaction ft = fm.beginTransaction();
+ final OperationDialogFragment fragment = new OperationDialogFragment();
+ fragment.setArguments(args);
+
+ ft.add(fragment, TAG);
+ ft.commitAllowingStateLoss();
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle inState) {
+ super.onCreate(inState);
+
+ final @DialogType int dialogType =
+ getArguments().getInt(FileOperationService.EXTRA_DIALOG_TYPE);
+ final @OpType int operationType =
+ getArguments().getInt(FileOperationService.EXTRA_OPERATION);
+ final ArrayList<DocumentInfo> srcList = getArguments().getParcelableArrayList(
+ FileOperationService.EXTRA_SRC_LIST);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ String messageFormat;
+
+ switch (dialogType) {
+ case DIALOG_TYPE_CONVERTED:
+ messageFormat = getString(R.string.copy_converted_warning_content);
+ break;
+
+ case DIALOG_TYPE_FAILURE:
+ switch (operationType) {
+ case FileOperationService.OPERATION_COPY:
+ messageFormat = getString(R.string.copy_failure_alert_content);
+ break;
+ case FileOperationService.OPERATION_MOVE:
+ messageFormat = getString(R.string.move_failure_alert_content);
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ break;
+
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ final StringBuilder list = new StringBuilder("<p>");
+ for (DocumentInfo documentInfo : srcList) {
+ list.append(String.format("• %s<br>", documentInfo.displayName));
+ }
+ list.append("</p>");
+ builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString())));
+ builder.setPositiveButton(
+ R.string.close,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
+
+ return builder.create();
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 82eb732..92ffb93 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -85,6 +85,8 @@
public static final String AUTHORITY = "authority";
public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+
+ @Deprecated // mode is tracked in local preferences now...by root only
public static final String MODE = "mode";
public static final String SORT_ORDER = "sortOrder";
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 2f0224f..28f7432 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import android.annotation.IntDef;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,18 +27,43 @@
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class State implements android.os.Parcelable {
+
+ 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_BROWSE = 6;
+ public static final int ACTION_PICK_COPY_DESTINATION = 8;
+
+ @IntDef(flag = true, value = {
+ MODE_UNKNOWN,
+ MODE_LIST,
+ MODE_GRID
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ViewMode {}
+ 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;
+
public int action;
public String[] acceptMimes;
- /** Explicit user choice */
- public int userMode = MODE_UNKNOWN;
- /** Derived after loader */
- public int derivedMode = MODE_GRID;
+ /** Derived from local preferences */
+ public @ViewMode int derivedMode = MODE_GRID;
/** Explicit user choice */
public int userSortOrder = SORT_ORDER_UNKNOWN;
@@ -58,6 +84,8 @@
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
+ private boolean mStackTouched;
+
/** Currently active search, overriding any stack. */
public String currentSearch;
@@ -70,25 +98,6 @@
/** Name of the package that started DocsUI */
public List<String> excludedAuthorities = new ArrayList<>();
- 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_BROWSE = 6;
- public static final int ACTION_PICK_COPY_DESTINATION = 8;
-
- 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;
-
- private boolean mStackTouched;
-
public void initAcceptMimes(Intent intent) {
if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
@@ -131,7 +140,6 @@
@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);
@@ -155,7 +163,6 @@
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;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 74fa8d0..2aabc99 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -20,7 +20,6 @@
import static com.android.documentsui.State.ACTION_MANAGE;
import static com.android.documentsui.State.MODE_GRID;
import static com.android.documentsui.State.MODE_LIST;
-import static com.android.documentsui.State.MODE_UNKNOWN;
import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -37,7 +36,6 @@
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ClipData;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
@@ -91,9 +89,6 @@
import com.android.documentsui.MimePredicate;
import com.android.documentsui.R;
import com.android.documentsui.RecentLoader;
-import com.android.documentsui.RecentsProvider;
-import com.android.documentsui.RecentsProvider.StateColumns;
-import com.android.documentsui.dirlist.RenameDocumentFragment;
import com.android.documentsui.RootsCache;
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
@@ -155,7 +150,6 @@
private int mType = TYPE_NORMAL;
private String mStateKey;
- private int mLastMode = MODE_UNKNOWN;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
private boolean mLastShowSize;
private DocumentsAdapter mAdapter;
@@ -240,7 +234,7 @@
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mIconHelper = new IconHelper(context, state.derivedMode);
+ mIconHelper = new IconHelper(context, MODE_GRID);
mAdapter = new SectionBreakDocumentsAdapterWrapper(
this, new ModelBackedDocumentsAdapter(this, mIconHelper));
@@ -323,12 +317,6 @@
if (!isAdded()) return;
mModel.update(result);
-
- // Push latest state up to UI
- // TODO: if mode change was racing with us, don't overwrite it
- if (result.mode != MODE_UNKNOWN) {
- state.derivedMode = result.mode;
- }
state.derivedSortOrder = result.sortOrder;
updateDisplayState();
@@ -361,8 +349,6 @@
// Kick off loader at least once
getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
-
- updateDisplayState();
}
@Override
@@ -425,61 +411,25 @@
state.dirState.put(mStateKey, container);
}
- @Override
- public void onResume() {
- super.onResume();
- updateDisplayState();
- }
-
public void onDisplayStateChanged() {
updateDisplayState();
}
- public void onUserSortOrderChanged() {
- // Sort order change always triggers reload; we'll trigger state change
- // on the flip side.
+ public void onSortOrderChanged() {
+ // Sort order is implemented as a sorting wrapper around directory
+ // results. So when sort order changes, we force a reload of the directory.
getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
}
- public void onUserModeChanged() {
- final ContentResolver resolver = getActivity().getContentResolver();
- final State state = getDisplayState();
-
- final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
- final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
-
- if (root != null && doc != null) {
- final Uri stateUri = RecentsProvider.buildState(
- root.authority, root.rootId, doc.documentId);
- final ContentValues values = new ContentValues();
- values.put(StateColumns.MODE, state.userMode);
-
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- resolver.insert(stateUri, values);
- return null;
- }
- }.execute();
- }
-
- // Mode change is just visual change; no need to kick loader, and
- // deliver change event immediately.
- state.derivedMode = state.userMode;
- ((BaseActivity) getActivity()).onStateChanged();
-
+ public void onViewModeChanged() {
+ // Mode change is just visual change; no need to kick loader.
updateDisplayState();
}
private void updateDisplayState() {
- final State state = getDisplayState();
-
- if (mLastMode == state.derivedMode && mLastShowSize == state.showSize) return;
- mLastMode = state.derivedMode;
+ State state = getDisplayState();
mLastShowSize = state.showSize;
-
updateLayout(state.derivedMode);
-
mRecView.setAdapter(mAdapter);
}
@@ -506,7 +456,6 @@
}
layout = mListLayout;
break;
- case MODE_UNKNOWN:
default:
throw new IllegalArgumentException("Unsupported layout mode: " + mode);
}
@@ -516,7 +465,7 @@
// setting layout manager automatically invalidates existing ViewHolders.
mRecView.setLayoutManager(layout);
mSelectionManager.handleLayoutChanged(); // RecyclerView doesn't do this for us
- mIconHelper.setMode(mode);
+ mIconHelper.setViewMode(mode);
}
private int calculateColumnCount() {
@@ -539,7 +488,6 @@
case MODE_LIST:
return getResources().getDimensionPixelSize(
R.dimen.list_container_padding);
- case MODE_UNKNOWN:
default:
throw new IllegalArgumentException("Unsupported layout mode: " + mode);
}
@@ -694,10 +642,7 @@
return true;
case R.id.menu_copy_to_clipboard:
- if (!selection.isEmpty()) {
- copySelectionToClipboard(selection);
- mode.finish();
- }
+ copySelectedToClipboard();
return true;
case R.id.menu_select_all:
@@ -716,6 +661,15 @@
}
}
+ public final boolean onBackPressed() {
+ if (mSelectionManager.hasSelection()) {
+ if (DEBUG) Log.d(TAG, "Clearing selection on back pressed.");
+ mSelectionManager.clearSelection();
+ return true;
+ }
+ return false;
+ }
+
private void cancelThumbnailTask(View view) {
final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
if (iconThumb != null) {
@@ -1045,6 +999,7 @@
Selection selection = mSelectionManager.getSelection(new Selection());
if (!selection.isEmpty()) {
copySelectionToClipboard(selection);
+ mSelectionManager.clearSelection();
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
index 0314077..53ed62e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -19,7 +19,6 @@
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.MODE_GRID;
import static com.android.documentsui.State.MODE_LIST;
-import static com.android.documentsui.State.MODE_UNKNOWN;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -42,6 +41,8 @@
import com.android.documentsui.ProviderExecutor;
import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.R;
+import com.android.documentsui.State;
+import com.android.documentsui.State.ViewMode;
import com.android.documentsui.ThumbnailCache;
/**
@@ -51,7 +52,9 @@
public class IconHelper {
private static String TAG = "IconHelper";
- private Context mContext;
+ private final Context mContext;
+
+ // Updated when icon size is set.
private ThumbnailCache mCache;
private Point mThumbSize;
// The display mode (MODE_GRID, MODE_LIST, etc).
@@ -64,7 +67,7 @@
*/
public IconHelper(Context context, int mode) {
mContext = context;
- setMode(mode);
+ setViewMode(mode);
mCache = DocumentsApplication.getThumbnailsCache(context, mThumbSize);
}
@@ -82,9 +85,14 @@
* Sets the current display mode. This affects the thumbnail sizes that are loaded.
* @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
*/
- public void setMode(int mode) {
- // TODO: Instead of exposing setMode, make the mode final, and make separate instances for
- // grid/list.
+ public void setViewMode(@ViewMode int mode) {
+ mMode = mode;
+ int thumbSize = getThumbSize(mode);
+ mThumbSize = new Point(thumbSize, thumbSize);
+ mCache = DocumentsApplication.getThumbnailsCache(mContext, mThumbSize);
+ }
+
+ private int getThumbSize(int mode) {
int thumbSize;
switch (mode) {
case MODE_GRID:
@@ -94,12 +102,10 @@
thumbSize = mContext.getResources().getDimensionPixelSize(
R.dimen.list_item_thumbnail_size);
break;
- case MODE_UNKNOWN:
default:
throw new IllegalArgumentException("Unsupported layout mode: " + mode);
}
- mMode = mode;
- mThumbSize = new Point(thumbSize, thumbSize);
+ return thumbSize;
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 68756a3..880da9c0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -19,7 +19,6 @@
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.MODE_GRID;
import static com.android.documentsui.State.MODE_LIST;
-import static com.android.documentsui.State.MODE_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -92,7 +91,6 @@
case MODE_LIST:
holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
break;
- case MODE_UNKNOWN:
default:
throw new IllegalStateException("Unsupported layout mode.");
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 1d8eba5..7c08ba7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -21,17 +21,23 @@
import static android.provider.DocumentsContract.buildDocumentUri;
import static android.provider.DocumentsContract.getDocumentId;
import static android.provider.DocumentsContract.isChildDocument;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_CONVERTED;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
+import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
+import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
import static com.google.common.base.Preconditions.checkArgument;
import android.annotation.StringRes;
import android.app.Notification;
import android.app.Notification.Builder;
+import android.app.PendingIntent;
import android.content.ContentProviderClient;
import android.content.Context;
+import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
@@ -44,6 +50,7 @@
import android.util.Log;
import android.webkit.MimeTypeMap;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -56,12 +63,14 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
+import java.util.ArrayList;
import java.util.List;
class CopyJob extends Job {
private static final String TAG = "CopyJob";
private static final int PROGRESS_INTERVAL_MILLIS = 1000;
final List<DocumentInfo> mSrcs;
+ final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>();
private long mStartTime = -1;
private long mBatchSize;
@@ -176,6 +185,29 @@
}
@Override
+ Notification getWarningNotification() {
+ final Intent navigateIntent = buildNavigateIntent();
+ navigateIntent.putExtra(EXTRA_DIALOG_TYPE, DIALOG_TYPE_CONVERTED);
+ navigateIntent.putExtra(EXTRA_OPERATION, operationType);
+
+ navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, convertedFiles);
+
+ // TODO: Consider adding a dialog on tapping the notification with a list of
+ // converted files.
+ final Notification.Builder warningBuilder = new Notification.Builder(service)
+ .setContentTitle(service.getResources().getString(
+ R.string.notification_copy_files_converted_title))
+ .setContentText(service.getString(
+ R.string.notification_touch_for_details))
+ .setContentIntent(PendingIntent.getActivity(appContext, 0, navigateIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT))
+ .setCategory(Notification.CATEGORY_ERROR)
+ .setSmallIcon(R.drawable.ic_menu_copy)
+ .setAutoCancel(true);
+ return warningBuilder.build();
+ }
+
+ @Override
void start() throws RemoteException {
mStartTime = elapsedRealtime();
@@ -183,10 +215,9 @@
mBatchSize = calculateSize(mSrcs);
DocumentInfo srcInfo;
- DocumentInfo dstInfo;
+ DocumentInfo dstInfo = stack.peek();
for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) {
srcInfo = mSrcs.get(i);
- dstInfo = stack.peek();
// Guard unsupported recursive operation.
if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
@@ -201,6 +232,12 @@
processDocument(srcInfo, null, dstInfo);
}
+ Metrics.logFileOperation(service, operationType, mSrcs, dstInfo);
+ }
+
+ @Override
+ boolean hasWarnings() {
+ return !convertedFiles.isEmpty();
}
/**
@@ -425,6 +462,10 @@
}
}
+ if (src.isVirtualDocument() && success) {
+ convertedFiles.add(src);
+ }
+
return success;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index eef696a..11c3a29 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -75,6 +76,11 @@
}
@Override
+ Notification getWarningNotification() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
void start() throws RemoteException {
for (DocumentInfo doc : mSrcs) {
if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
@@ -85,6 +91,7 @@
onFileFailed(doc);
}
}
+ Metrics.logFileOperation(service, operationType, mSrcs, null);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 5d74cdc..3a025c2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -55,6 +55,7 @@
private static final int POOL_SIZE = 2; // "pool size", not *max* "pool size".
private static final int NOTIFICATION_ID_PROGRESS = 0;
private static final int NOTIFICATION_ID_FAILURE = 1;
+ private static final int NOTIFICATION_ID_WARNING = 2;
public static final String TAG = "FileOperationService";
@@ -63,7 +64,7 @@
public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION";
public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
- public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
+ public static final String EXTRA_DIALOG_TYPE = "com.android.documentsui.DIALOG_TYPE";
// This extra is used only for moving and deleting. Currently it's not the case,
// but in the future those files may be from multiple different parents. In
@@ -306,6 +307,18 @@
// Dismiss the ongoing copy notification when the copy is done.
mNotificationManager.cancel(job.id, NOTIFICATION_ID_PROGRESS);
+ if (job.hasFailures()) {
+ Log.e(TAG, "Job failed on files: " + job.failedFiles.size() + ".");
+ mNotificationManager.notify(
+ job.id, NOTIFICATION_ID_FAILURE, job.getFailureNotification());
+ }
+
+ if (job.hasWarnings()) {
+ if (DEBUG) Log.d(TAG, "Job finished with warnings.");
+ mNotificationManager.notify(
+ job.id, NOTIFICATION_ID_WARNING, job.getWarningNotification());
+ }
+
synchronized (mRunning) {
deleteJob(job);
}
@@ -318,15 +331,6 @@
job.id, NOTIFICATION_ID_PROGRESS, job.getProgressNotification());
}
- @Override
- public void onFailed(Job job) {
- if (DEBUG) Log.d(TAG, "onFailed: " + job.id);
- checkArgument(job.failed());
- Log.e(TAG, "Job failed on files: " + job.failedFiles.size() + ".");
- mNotificationManager.notify(job.id, NOTIFICATION_ID_FAILURE, job.getFailureNotification());
- onFinished(job); // Failed jobs don't call finished, so we do.
- }
-
private static final class JobRecord {
private final Job job;
private final ScheduledFuture<?> future;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 9534d6c..f2c8763 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -18,11 +18,10 @@
import static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow;
import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
-import static com.android.documentsui.services.FileOperationService.EXTRA_FAILURE;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
-import static com.android.documentsui.services.FileOperationService.FAILURE_COPY;
import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -42,6 +41,8 @@
import android.util.Log;
import com.android.documentsui.FilesActivity;
+import com.android.documentsui.Metrics;
+import com.android.documentsui.OperationDialogFragment;
import com.android.documentsui.R;
import com.android.documentsui.Shared;
import com.android.documentsui.model.DocumentInfo;
@@ -57,8 +58,7 @@
* A mashup of work item and ui progress update factory. Used by {@link FileOperationService}
* to do work and show progress relating to this work.
*/
-abstract class Job implements Runnable {
-
+abstract public class Job implements Runnable {
private static final String TAG = "Job";
final Context service;
final Context appContext;
@@ -114,13 +114,10 @@
// to resolve business in an orderly fashion. That'll
// ensure the service is shut down and notifications
// shown/closed.
- listener.onFailed(this);
+ Log.e(TAG, "Operation failed due to an exception.", e);
+ Metrics.logFileOperationErrors(service, operationType, failedFiles);
} finally {
- if (failed()) {
- listener.onFailed(this);
- } else {
- listener.onFinished(this);
- }
+ listener.onFinished(this);
}
}
@@ -131,6 +128,8 @@
// abstract Notification getProgressNotification(long bytesCopied);
abstract Notification getFailureNotification();
+ abstract Notification getWarningNotification();
+
ContentProviderClient getClient(DocumentInfo doc) throws RemoteException {
ContentProviderClient client = mClients.get(doc.authority);
if (client == null) {
@@ -153,6 +152,7 @@
final void cancel() {
mCanceled = true;
+ Metrics.logFileOperationCancelled(service, operationType);
}
final boolean isCanceled() {
@@ -167,10 +167,14 @@
failedFiles.add(file);
}
- final boolean failed() {
+ final boolean hasFailures() {
return !failedFiles.isEmpty();
}
+ boolean hasWarnings() {
+ return false;
+ }
+
final boolean deleteDocument(DocumentInfo doc) {
try {
DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
@@ -190,7 +194,7 @@
Notification getFailureNotification(@PluralsRes int titleId, @DrawableRes int icon) {
final Intent navigateIntent = buildNavigateIntent();
- navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+ navigateIntent.putExtra(EXTRA_DIALOG_TYPE, OperationDialogFragment.DIALOG_TYPE_FAILURE);
navigateIntent.putExtra(EXTRA_OPERATION, operationType);
navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, failedFiles);
@@ -291,7 +295,6 @@
*/
interface Listener {
void onStart(Job job);
- void onFailed(Job job);
void onFinished(Job job);
void onProgress(CopyJob job);
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
index 9c58780..a1c6dab 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -63,6 +63,11 @@
}
@Override
+ Notification getWarningNotification() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
Builder createProgressBuilder() {
// the "copy" stuff was just convenient and available :)
return super.createProgressBuilder(
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
index 0110197..46b093d 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
@@ -33,7 +33,6 @@
private final CountDownLatch latch = new CountDownLatch(1);
private final List<Job> progress = new ArrayList<>();
@Nullable private Job started;
- @Nullable private Job failed;
@Nullable private Job finished;
@Override
@@ -42,11 +41,6 @@
}
@Override
- public void onFailed(Job job) {
- failed = job;
- }
-
- @Override
public void onFinished(Job job) {
this.finished = job;
latch.countDown();
@@ -70,28 +64,28 @@
}
public void assertFailed() {
- if (failed == null) {
+ if (finished == null || !finished.hasFailures()) {
fail("Job didn't fail. onFailed never called.");
}
}
public void assertFilesFailed(ArrayList<String> names) {
- if (failed == null) {
+ if (finished == null || !finished.hasFailures()) {
fail("Can't test failed documetns. Job didn't fail.");
}
- assertEquals(failed.failedFiles.size(), names.size());
+ assertEquals(finished.failedFiles.size(), names.size());
for (String name : names) {
assertFileFailed(name);
}
}
public void assertFileFailed(String name) {
- if (failed == null) {
+ if (finished == null || !finished.hasFailures()) {
fail("Can't test failed documetns. Job didn't fail.");
}
- for (DocumentInfo failed : failed.failedFiles) {
+ for (DocumentInfo failed : finished.failedFiles) {
if (name.equals(failed.displayName)) {
return;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index cbf22c0..40c11cf 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -29,6 +29,7 @@
import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.widget.LockPatternUtils;
@@ -117,7 +118,7 @@
* Shows the emergency dialer or returns the user to the existing call.
*/
public void takeEmergencyCallAction() {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_EMERGENCY_CALL);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL);
// TODO: implement a shorter timeout once new PowerManager API is ready.
// should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index c7d17dc..409f6a7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
-import android.auditing.SecurityLog;
import android.content.Context;
import android.os.UserHandle;
import android.util.AttributeSet;
@@ -424,11 +423,6 @@
}
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
- if (SecurityLog.isLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_UNLOCK_ATTEMPT,
- (success ? 1 : 0),
- mCurrentSecuritySelection.name());
- }
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
if (success) {
monitor.clearFailedUnlockAttempts();
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
index 7b57d89..2b44d51 100644
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -50,7 +50,8 @@
static jclass app_fuse_class;
static jmethodID app_fuse_get_file_size;
-static jmethodID app_fuse_get_object_bytes;
+static jmethodID app_fuse_read_object_bytes;
+static jfieldID app_fuse_buffer;
// NOTE:
// FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
@@ -282,7 +283,7 @@
out->prepare_buffer(0);
const int64_t result = get_object_bytes(it->second, offset, size, out->data());
if (result < 0) {
- return -EIO;
+ return result;
}
out->set_size(result);
return 0;
@@ -332,20 +333,24 @@
uint64_t offset,
uint32_t size,
void* buf) {
- ScopedLocalRef<jbyteArray> array(env_, static_cast<jbyteArray>(env_->CallObjectMethod(
+ const jlong read_size = env_->CallLongMethod(
self_,
- app_fuse_get_object_bytes,
- inode,
- offset,
- size)));
+ app_fuse_read_object_bytes,
+ static_cast<jint>(inode),
+ static_cast<jlong>(offset),
+ static_cast<jlong>(size));
+ if (read_size <= 0) {
+ return read_size;
+ }
+ ScopedLocalRef<jbyteArray> array(
+ env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
if (array.get() == nullptr) {
- return -1;
+ return -EFAULT;
}
ScopedByteArrayRO bytes(env_, array.get());
if (bytes.get() == nullptr) {
- return -1;
+ return -ENOMEM;
}
- const uint32_t read_size = std::min(static_cast<uint32_t>(bytes.size()), size);
memcpy(buf, bytes.get(), read_size);
return read_size;
}
@@ -451,10 +456,16 @@
return -1;
}
- app_fuse_get_object_bytes = env->GetMethodID(
- app_fuse_class, "getObjectBytes", "(IJI)[B");
- if (app_fuse_get_object_bytes == nullptr) {
- ALOGE("Can't find getObjectBytes");
+ app_fuse_read_object_bytes = env->GetMethodID(
+ app_fuse_class, "readObjectBytes", "(IJJ)J");
+ if (app_fuse_read_object_bytes == nullptr) {
+ ALOGE("Can't find readObjectBytes");
+ return -1;
+ }
+
+ app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
+ if (app_fuse_buffer == nullptr) {
+ ALOGE("Can't find mBuffer");
return -1;
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 1300c47..6a98405 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -16,9 +16,11 @@
package com.android.mtp;
+import android.annotation.WorkerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.storage.StorageManager;
+import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -40,6 +42,13 @@
private final String mName;
private final Callback mCallback;
+
+ /**
+ * Buffer for read bytes request.
+ * Don't use the buffer from the out of AppFuseMessageThread.
+ */
+ private byte[] mBuffer = new byte[MAX_READ];
+
private Thread mMessageThread;
private ParcelFileDescriptor mDeviceFd;
@@ -82,28 +91,48 @@
}
static interface Callback {
+ /**
+ * Returns file size for the given inode.
+ * @param inode
+ * @return File size. Must not be negative.
+ * @throws FileNotFoundException
+ */
long getFileSize(int inode) throws FileNotFoundException;
- byte[] getObjectBytes(int inode, long offset, int size) throws IOException;
+
+ /**
+ * Returns flie bytes for the give inode.
+ * @param inode
+ * @param offset Offset for file bytes.
+ * @param size Size for file bytes.
+ * @param bytes Buffer to store file bytes.
+ * @return Number of read bytes. Must not be negative.
+ * @throws IOException
+ */
+ long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
}
@UsedByNative("com_android_mtp_AppFuse.cpp")
+ @WorkerThread
private long getFileSize(int inode) {
try {
return mCallback.getFileSize(inode);
- } catch (IOException e) {
- return -1;
+ } catch (FileNotFoundException e) {
+ return -OsConstants.ENOENT;
}
}
@UsedByNative("com_android_mtp_AppFuse.cpp")
- private byte[] getObjectBytes(int inode, long offset, int size) {
+ @WorkerThread
+ private long readObjectBytes(int inode, long offset, long size) {
if (offset < 0 || size < 0 || size > MAX_READ) {
- return null;
+ return -OsConstants.EINVAL;
}
try {
- return mCallback.getObjectBytes(inode, offset, size);
+ // It's OK to share the same mBuffer among requests because the requests are processed
+ // by AppFuseMessageThread sequentially.
+ return mCallback.readObjectBytes(inode, offset, size, mBuffer);
} catch (IOException e) {
- return null;
+ return -OsConstants.EIO;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 112914e..959fac6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -165,22 +165,27 @@
cursor.close();
}
- long capacityBytes = 0;
- long availableBytes = 0;
- int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
- int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
- while (storageCursor.moveToNext()) {
- // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
- // calculate corresponding values.
- if (capacityIndex != -1) {
- capacityBytes += cursor.getLong(capacityIndex);
+ if (storageCursor.getCount() != 0) {
+ long capacityBytes = 0;
+ long availableBytes = 0;
+ int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+ int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+ while (storageCursor.moveToNext()) {
+ // If requested columnNames does not include COLUMN_XXX_BYTES, we
+ // don't calculate corresponding values.
+ if (capacityIndex != -1) {
+ capacityBytes += cursor.getLong(capacityIndex);
+ }
+ if (availableIndex != -1) {
+ availableBytes += cursor.getLong(availableIndex);
+ }
}
- if (availableIndex != -1) {
- availableBytes += cursor.getLong(availableIndex);
- }
+ values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+ values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+ } else {
+ values.putNull(Root.COLUMN_CAPACITY_BYTES);
+ values.putNull(Root.COLUMN_AVAILABLE_BYTES);
}
- values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
- values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
}
} finally {
storageCursor.close();
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 3ac1b3d..6b5f16a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -16,8 +16,6 @@
package com.android.mtp;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -40,7 +38,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -391,16 +388,12 @@
}
private class AppFuseCallback implements AppFuse.Callback {
- final byte[] mBytes = new byte[AppFuse.MAX_READ];
-
@Override
- public byte[] getObjectBytes(int inode, long offset, int size) throws IOException {
+ public long readObjectBytes(
+ int inode, long offset, long size, byte[] buffer) throws IOException {
final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
- final long readSize = mMtpManager.getPartialObject(
- identifier.mDeviceId, identifier.mObjectHandle, offset, size, mBytes);
- // TODO: Change signature so that getObjectBytes can return read size without copying
- // bytes.
- return Arrays.copyOf(mBytes, (int) readSize);
+ return mMtpManager.getPartialObject(
+ identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
}
@Override
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
index 6354880..c0973bd 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -77,30 +77,35 @@
public void testReadFile() throws IOException {
final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
- final int INODE = 10;
- final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+ final int fileInode = 10;
+ final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' };
final AppFuse appFuse = new AppFuse(
"test",
new TestCallback() {
@Override
public long getFileSize(int inode) throws FileNotFoundException {
- if (inode == INODE) {
- return BYTES.length;
+ if (inode == fileInode) {
+ return fileBytes.length;
}
return super.getFileSize(inode);
}
@Override
- public byte[] getObjectBytes(int inode, long offset, int size)
+ public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
throws IOException {
- if (inode == INODE) {
- return Arrays.copyOfRange(BYTES, (int) offset, (int) offset + size);
+ if (inode == fileInode) {
+ int i = 0;
+ while (i < size && i + offset < fileBytes.length) {
+ bytes[i] = fileBytes[(int) (i + offset)];
+ i++;
+ }
+ return i;
}
- return super.getObjectBytes(inode, offset, size);
+ return super.readObjectBytes(inode, offset, size, bytes);
}
});
appFuse.mount(storageManager);
- final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+ final ParcelFileDescriptor fd = appFuse.openFile(fileInode);
try (final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
final byte[] buffer = new byte[1024];
@@ -117,7 +122,7 @@
}
@Override
- public byte[] getObjectBytes(int inode, long offset, int size)
+ public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
throws IOException {
throw new IOException();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 97ea717..8075999 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -899,4 +899,24 @@
mDatabase.getMapper().stopAddingDocuments(null);
assertEquals("1", mDatabase.getDocumentIdForDevice(100));
}
+
+ public void testGetClosedDevice() {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ final String[] columns = new String [] {
+ DocumentsContract.Root.COLUMN_ROOT_ID,
+ DocumentsContract.Root.COLUMN_TITLE,
+ DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
+ };
+ try (final Cursor cursor = mDatabase.queryRoots(columns)) {
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(1, cursor.getLong(0));
+ assertEquals("Device", cursor.getString(1));
+ assertTrue(cursor.isNull(2));
+ }
+ }
}
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index a2f710d..2db6fb0 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -125,8 +125,8 @@
<android.support.v7.widget.RecyclerView
android:id="@+id/preview_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical">
</android.support.v7.widget.RecyclerView>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index d3c1364..210682f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.graphics.Color;
@@ -178,7 +179,7 @@
if (userInfo.isManagedProfile()) {
// If userInfo.id is a managed profile, we also need to look at
// the policies set on the parent.
- DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+ DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
& keyguardFeatures) != 0) {
if (enforcedAdmin == null) {
@@ -227,6 +228,26 @@
}
/**
+ * Check if an application is suspended.
+ *
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} if the application is not suspended.
+ */
+ public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
+ int userId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
+ if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+ return getProfileOrDeviceOwnerOnCallingUser(context);
+ }
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ return null;
+ }
+
+ /**
* Check if account management for a specific type of account is disabled by admin.
* Only a profile or device owner can disable account management. So, we check if account
* management is disabled and return profile or device owner on the calling user.
@@ -375,7 +396,7 @@
if (userInfo.isManagedProfile()) {
// If userInfo.id is a managed profile, we also need to look at
// the policies set on the parent.
- DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+ DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
if (enforcedAdmin == null) {
enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index f1beb10..5c8849d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -29,7 +29,6 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -56,6 +55,7 @@
private final UserManager mUserManager;
private final UserHandle mUser;
private final boolean mRestrictedProfile;
+ private boolean mLeanback;
HashMap<String,Boolean> mSelectedPackages = new HashMap<>();
private List<SelectableAppInfo> mVisibleApps;
@@ -77,6 +77,10 @@
return mSelectedPackages.get(packageName);
}
+ public void setLeanback(boolean isLeanback) {
+ mLeanback = isLeanback;
+ }
+
public List<SelectableAppInfo> getVisibleApps() {
return mVisibleApps;
}
@@ -155,7 +159,11 @@
// Add launchers
Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
- launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ if (mLeanback) {
+ launcherIntent.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+ } else {
+ launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ }
addSystemApps(mVisibleApps, launcherIntent, excludePackages);
// Add widgets
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 2ee4b12..5b8ed28 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -37,6 +37,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.support.annotation.NonNull;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -104,7 +105,8 @@
private static final int PSK_WPA2 = 2;
private static final int PSK_WPA_WPA2 = 3;
- private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
+ public static final int SIGNAL_LEVELS = 4;
+
private final Context mContext;
private String ssid;
@@ -167,7 +169,7 @@
}
@Override
- public int compareTo(AccessPoint other) {
+ public int compareTo(@NonNull AccessPoint other) {
// Active one goes first.
if (isActive() && !other.isActive()) return -1;
if (!isActive() && other.isActive()) return 1;
@@ -182,8 +184,9 @@
if (networkId == WifiConfiguration.INVALID_NETWORK_ID
&& other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
- // Sort by signal strength.
- int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+ // Sort by signal strength, bucketed by level
+ int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
+ - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
if (difference != 0) {
return difference;
}
@@ -260,7 +263,7 @@
if (mRssi == Integer.MAX_VALUE) {
return -1;
}
- return WifiManager.calculateSignalLevel(mRssi, 4);
+ return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
}
public int getRssi() {
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 5b83796..a93caca 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -786,7 +786,8 @@
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(mimeType);
- final String subject = info.title != null ? info.title : bugreportUri.getLastPathSegment();
+ final String subject = !TextUtils.isEmpty(info.title) ?
+ info.title : bugreportUri.getLastPathSegment();
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
// EXTRA_TEXT should be an ArrayList, but some clients are expecting a single String.
@@ -832,7 +833,7 @@
+ mProcesses + "), using info from intent instead (" + info + ")");
}
- addDetailsToZipFile(info);
+ addDetailsToZipFile(mContext, info);
final Intent sendIntent = buildSendIntent(mContext, info);
final Intent notifIntent;
@@ -856,6 +857,10 @@
* Sends a notification indicating the bugreport has finished so use can share it.
*/
private static void sendBugreportNotification(Context context, BugreportInfo info) {
+
+ // Since adding the details can take a while, do it before notifying user.
+ addDetailsToZipFile(context, info);
+
final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
shareIntent.setClass(context, BugreportProgressService.class);
shareIntent.setAction(INTENT_BUGREPORT_SHARE);
@@ -949,7 +954,7 @@
* If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
* description will be saved on {@code description.txt}.
*/
- private void addDetailsToZipFile(BugreportInfo info) {
+ private static void addDetailsToZipFile(Context context, BugreportInfo info) {
if (info.bugreportFile == null) {
// One possible reason is a bug in the Parcelization code.
Log.e(TAG, "INTERNAL ERROR: no bugreportFile on " + info);
@@ -959,10 +964,15 @@
Log.d(TAG, "Not touching zip file since neither title nor description are set");
return;
}
+ if (info.addedDetailsToZip || info.addingDetailsToZip) {
+ Log.d(TAG, "Already added details to zip file for " + info);
+ return;
+ }
+ info.addingDetailsToZip = true;
// It's not possible to add a new entry into an existing file, so we need to create a new
// zip, copy all entries, then rename it.
- sendBugreportBeingUpdatedNotification(mContext, info.pid); // ...and that takes time
+ sendBugreportBeingUpdatedNotification(context, info.pid); // ...and that takes time
final File dir = info.bugreportFile.getParentFile();
final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -985,6 +995,7 @@
addEntry(zos, "title.txt", info.title);
addEntry(zos, "description.txt", info.description);
} catch (IOException e) {
+ info.addingDetailsToZip = false;
Log.e(TAG, "exception zipping file " + tmpZip, e);
return;
}
@@ -992,6 +1003,8 @@
if (!tmpZip.renameTo(info.bugreportFile)) {
Log.e(TAG, "Could not rename " + tmpZip + " to " + info.bugreportFile);
}
+ info.addedDetailsToZip = true;
+ info.addingDetailsToZip = false;
}
private static void addEntry(ZipOutputStream zos, String entry, String text)
@@ -1387,6 +1400,12 @@
boolean finished;
/**
+ * Whether the details entries have been added to the bugreport yet.
+ */
+ boolean addingDetailsToZip;
+ boolean addedDetailsToZip;
+
+ /**
* Internal counter used to name screenshot files.
*/
int screenshotCounter;
@@ -1466,7 +1485,9 @@
+ "\n\ttitle: " + title + "\n\tdescription: " + description
+ "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
+ "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
- + "\n\tlast_update: " + getFormattedLastUpdate();
+ + "\n\tlast_update: " + getFormattedLastUpdate()
+ + "\naddingDetailsToZip: " + addingDetailsToZip
+ + " addedDetailsToZip: " + addedDetailsToZip;
}
// Parcelable contract
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 5908d02..ea85c61 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -114,6 +114,8 @@
private static final String NO_SCREENSHOT = null;
private static final String NO_TITLE = null;
private static final Integer NO_PID = null;
+ private static final boolean RENAMED_SCREENSHOTS = true;
+ private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
private String mDescription;
@@ -171,7 +173,7 @@
Bundle extras =
sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
- NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+ NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
@@ -202,7 +204,7 @@
Bundle extras = acceptBugreportAndGetSharedIntent();
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
- NAME, NO_TITLE, NO_DESCRIPTION, 2, true);
+ NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
@@ -231,13 +233,12 @@
Bundle extras = acceptBugreportAndGetSharedIntent();
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE,
- NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+ NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
public void testProgress_changeDetailsInvalidInput() throws Exception {
-
resetProperties();
sendBugreportStarted(1000);
waitForScreenshotButtonEnabled(true);
@@ -277,7 +278,7 @@
Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
- NEW_NAME, TITLE, mDescription, 1, true);
+ NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
@@ -291,7 +292,6 @@
}
public void changeDetailsTest(boolean plainText) throws Exception {
-
resetProperties();
sendBugreportStarted(1000);
waitForScreenshotButtonEnabled(true);
@@ -316,7 +316,26 @@
Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
plainText? mPlainTextPath : mZipPath, mScreenshotPath);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
- NEW_NAME, TITLE, mDescription, 1, true);
+ NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
+
+ assertServiceNotRunning();
+ }
+
+ public void testProgress_changeJustDetails() throws Exception {
+ resetProperties();
+ sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
+
+ DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+ detailsUi.nameField.setText("");
+ detailsUi.titleField.setText("");
+ detailsUi.descField.setText(mDescription);
+ detailsUi.clickOk();
+
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mZipPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+ NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS);
assertServiceNotRunning();
}
@@ -367,7 +386,7 @@
// Finally, share bugreport.
Bundle extras = acceptBugreportAndGetSharedIntent();
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
- NAME, TITLE, mDescription, 1, true);
+ NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
@@ -539,7 +558,7 @@
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
String screenshotContent) throws IOException {
assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE,
- NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, false);
+ NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
}
/**
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index e4d0fec..88313bb 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -12,6 +12,7 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
+ android-support-v17-leanback \
framework-protos
LOCAL_JAVA_LIBRARIES := telephony-common
@@ -30,10 +31,12 @@
frameworks/support/v7/preference/res \
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
- frameworks/support/v7/recyclerview/res
+ frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat
+ --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
+ --extra-packages android.support.v17.leanback
ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 21abb90..2713fb5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -236,6 +236,20 @@
</intent-filter>
</activity>
+ <activity android:name=".recents.tv.RecentsTvActivity"
+ android:label="@string/accessibility_desc_recent_apps"
+ android:exported="false"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:stateNotNeeded="true"
+ android:resumeWhilePausing="true"
+ android:screenOrientation="behind"
+ android:theme="@style/RecentsTheme.Wallpaper">
+ <intent-filter>
+ <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+ </intent-filter>
+ </activity>
+
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
android:process=":screenshot"
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 2ea8c9c..d0c2d29 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -35,3 +35,4 @@
}
-keep class ** extends android.support.v14.preference.PreferenceFragment
+-keep class com.android.systemui.tuner.*
diff --git a/packages/SystemUI/res/drawable/clipboard_empty.xml b/packages/SystemUI/res/drawable/clipboard_empty.xml
new file mode 100644
index 0000000..14a5ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_empty.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the License);
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an AS IS BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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="#FFFFFFFF"
+ android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/clipboard_full.xml b/packages/SystemUI/res/drawable/clipboard_full.xml
new file mode 100644
index 0000000..2d46870
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_full.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the License);
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an AS IS BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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="#FFFFFFFF"
+ android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z M 6,8 l 12,0 l 0,11 l -12,0 l 0,-11z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_drag_handle.xml b/packages/SystemUI/res/drawable/ic_drag_handle.xml
new file mode 100644
index 0000000..9b319f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_drag_handle.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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="#FFFFFFFF"
+ android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_history.xml b/packages/SystemUI/res/drawable/ic_history.xml
new file mode 100644
index 0000000..e936864
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_history.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89 .07 .14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7
+7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13
+21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54 .72 -1.21-3.5-2.08V8H12z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
new file mode 100644
index 0000000..b4144a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="40.0"
+ android:viewportHeight="40.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_width.xml b/packages/SystemUI/res/drawable/ic_width.xml
new file mode 100644
index 0000000..a302c81
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_width.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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="M7.77,6.76L6.23,5.4 0.82,12.0l5.41,6.52 1.54,-1.28L3.42,12.0l4.35,-5.24z
+ M17.77,5.48l-1.54,1.28L20.58,12.0l-4.35,5.24 1.54,1.28L23.18,12.0l-5.41,-6.52z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M2.0,13.0l20.0,0.0l0.0,-2.0l-20.0,0.0l0.0,2.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
new file mode 100644
index 0000000..6a417e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
@@ -0,0 +1,54 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2 (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:height="16dp"
+ android:width="28dp"
+ android:viewportHeight="48"
+ android:viewportWidth="72" >
+ <group
+ android:name="dismiss_all"
+ android:translateX="48"
+ android:translateY="6" >
+ <group
+ android:name="3"
+ android:translateX="-24"
+ android:translateY="36" >
+ <path
+ android:name="rectangle_path_1_2"
+ android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ <group
+ android:name="2"
+ android:translateX="-12"
+ android:translateY="18" >
+ <path
+ android:name="rectangle_path_1_1"
+ android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ <group
+ android:name="1" >
+ <path
+ android:name="rectangle_path_1"
+ android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml b/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml
deleted file mode 100644
index 5f9341c..0000000
--- a/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners android:topLeftRadius="@dimen/recents_task_view_rounded_corners_radius"
- android:topRightRadius="@dimen/recents_task_view_rounded_corners_radius"/>
- <solid android:color="#00000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
new file mode 100644
index 0000000..4e2a024
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="40.0"
+ android:viewportHeight="40.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml b/packages/SystemUI/res/drawable/switchbar_background.xml
similarity index 85%
rename from packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
rename to packages/SystemUI/res/drawable/switchbar_background.xml
index 745af33..8d97c46 100644
--- a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
+++ b/packages/SystemUI/res/drawable/switchbar_background.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,5 +16,6 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@android:color/transparent" />
-</ripple>
\ No newline at end of file
+ <item android:drawable="@color/switch_bar_background" />
+</ripple>
+
diff --git a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..a430b73
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:elevation="4dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:background="@android:color/white"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/preview"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:textColor="?android:attr/colorAccent"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <FrameLayout
+ android:id="@+id/nav_preview_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="12dp"
+ android:paddingEnd="12dp"
+ android:layout_gravity="bottom"
+ android:background="@android:color/white"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preview"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/colorAccent"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <FrameLayout
+ android:id="@+id/nav_preview_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/clipboard.xml b/packages/SystemUI/res/layout/clipboard.xml
new file mode 100644
index 0000000..441d6737
--- /dev/null
+++ b/packages/SystemUI/res/layout/clipboard.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.tuner.ClipboardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="@dimen/navigation_side_padding"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="center"
+ android:contentDescription="@string/clipboard"
+ />
+
diff --git a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml b/packages/SystemUI/res/layout/color_matrix_settings.xml
similarity index 66%
copy from packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
copy to packages/SystemUI/res/layout/color_matrix_settings.xml
index 745af33..3725e78 100644
--- a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
+++ b/packages/SystemUI/res/layout/color_matrix_settings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,11 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@android:color/transparent" />
-</ripple>
\ No newline at end of file
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/switch_bar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/custom_key.xml b/packages/SystemUI/res/layout/custom_key.xml
new file mode 100644
index 0000000..0b5cb72
--- /dev/null
+++ b/packages/SystemUI/res/layout/custom_key.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.statusbar.policy.KeyButtonView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="@dimen/navigation_side_padding"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="center"
+ android:tint="@android:color/white"
+ android:contentDescription="@string/accessibility_key" />
+
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
new file mode 100644
index 0000000..5a6553f
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_shortcuts_keyword_wrapper"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:paddingBottom="8dp">
+ <TextView
+ android:id="@+id/keyboard_shortcuts_keyword"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="12dp"
+ android:background="@android:color/white"
+ android:textColor="#D9000000"
+ android:textSize="16sp"
+ android:maxLines="5"
+ android:singleLine="false"
+ android:scrollHorizontally="false"
+ android:layout_alignParentStart="true"
+ android:minWidth="100dp"
+ android:maxWidth="260dp"/>
+ <!--TODO: introduce and use a layout that allows wrapping and right align -->
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_item_container"
+ android:layout_toEndOf="@+id/keyboard_shortcuts_keyword"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/white"
+ android:layout_alignParentEnd="true"
+ android:gravity="end"
+ android:textSize="14sp"
+ android:paddingStart="0dp"
+ android:paddingEnd="0dp"
+ android:scrollHorizontally="false"
+ android:minWidth="100dp"
+ android:maxWidth="260dp"/>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
new file mode 100644
index 0000000..80a478a
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textSize="14sp"
+ android:paddingStart="24dp"
+ android:paddingTop="20dp"
+ android:paddingEnd="24dp"
+ android:paddingBottom="13dp" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
new file mode 100644
index 0000000..fa07eb1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
new file mode 100644
index 0000000..5002c12
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:padding="4dp"
+ android:background="#EEEEEE"
+ android:textColor="#8C000000"
+ android:singleLine="true"
+ android:textSize="14sp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index 460433e..77b1264 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
+ ~ Copyright (C) 2016 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,11 +14,25 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyboard_shortcuts_wrapper"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="40dp"
- android:focusable="true">
-</RelativeLayout>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_shortcuts_wrapper"
+ android:layout_width="488dp"
+ android:layout_height="wrap_content"
+ android:focusable="true">
+ <ScrollView
+ android:id="@+id/keyboard_shortcuts_scroll_view"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+ </ScrollView>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
new file mode 100644
index 0000000..802acfe
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner.xml b/packages/SystemUI/res/layout/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="12dp"
+ android:paddingEnd="12dp"
+ android:layout_gravity="bottom"
+ android:background="@android:color/white"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/preview"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/colorAccent"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <FrameLayout
+ android:id="@+id/nav_preview_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
new file mode 100644
index 0000000..b237633
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.tuner.PreviewNavInflater
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:background="@android:color/black"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/navigation_bar_size">
+
+ <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
+
+ <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
+
+</com.android.systemui.tuner.PreviewNavInflater>
diff --git a/packages/SystemUI/res/layout/nav_control_widget.xml b/packages/SystemUI/res/layout/nav_control_widget.xml
new file mode 100644
index 0000000..51dd68f
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_control_widget.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/width"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_width"
+ android:clickable="true"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <ImageView
+ android:id="@+id/close"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_close"
+ android:clickable="true"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <ImageView
+ android:id="@+id/drag"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_drag_handle"
+ android:clickable="true"
+ android:tint="?android:attr/textColorPrimary" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_width_view.xml b/packages/SystemUI/res/layout/nav_width_view.xml
new file mode 100644
index 0000000..6a72faf
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_width_view.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<SeekBar
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/seekbar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:paddingTop="12dp"
+ android:paddingBottom="4dp" />
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/preference_matrix.xml
index ebf486f..1f6066e 100644
--- a/packages/SystemUI/res/layout/preference_matrix.xml
+++ b/packages/SystemUI/res/layout/preference_matrix.xml
@@ -19,82 +19,86 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Space
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" />
- <GridLayout
- android:id="@+id/edit_group"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:rowCount="5"
- android:columnCount="5">
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical">
- <Space android:layout_width="40dp" />
+ <LinearLayout
+ android:id="@+id/r_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:orientation="horizontal">
<TextView
- android:layout_width="40dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/color_modification_r"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium" />
+ <SeekBar android:id="@*android:id/seekbar"
+ android:layout_marginStart="16dp"
+ android:layout_gravity="center_vertical"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/g_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:orientation="horizontal">
+
<TextView
- android:layout_width="40dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/color_modification_g"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium" />
+ <SeekBar android:id="@*android:id/seekbar"
+ android:layout_marginStart="16dp"
+ android:layout_gravity="center_vertical"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/b_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:orientation="horizontal">
+
<TextView
- android:layout_width="40dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/color_modification_b"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium" />
- <Space android:layout_width="40dp" />
+ <SeekBar android:id="@*android:id/seekbar"
+ android:layout_marginStart="16dp"
+ android:layout_gravity="center_vertical"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ </LinearLayout>
- <TextView
- android:layout_width="40dp"
- android:text="@string/color_modification_r"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
- <TextView
- android:layout_width="40dp"
- android:text="@string/color_modification_g"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
- <TextView
- android:layout_width="40dp"
- android:text="@string/color_modification_b"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
- <Space android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
- <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
-
- </GridLayout>
<Button
android:id="@+id/apply"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="bottom"
+ android:layout_gravity="end"
android:text="@string/color_apply" />
+
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 16ff14c..186aaf6 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -17,14 +17,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <!-- Status Bar Scrim View -->
- <ImageView
- android:id="@+id/status_bar_scrim"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|top"
- android:scaleType="fitXY"
- android:src="@drawable/recents_status_gradient" />
<!-- Recents View -->
<com.android.systemui.recents.views.RecentsView
@@ -33,12 +25,6 @@
android:layout_height="match_parent">
</com.android.systemui.recents.views.RecentsView>
- <!-- History View -->
- <ViewStub android:id="@+id/history_view_stub"
- android:layout="@layout/recents_history"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<!-- Nav Bar Scrim View -->
<ImageView
android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index 4b68e77..b2c0331 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -24,5 +24,4 @@
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif"
- android:background="#80000000"
android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history.xml b/packages/SystemUI/res/layout/recents_history.xml
index b65a5c5..dc2da72 100644
--- a/packages/SystemUI/res/layout/recents_history.xml
+++ b/packages/SystemUI/res/layout/recents_history.xml
@@ -17,7 +17,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#99000000"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
index 8c96fc6..538bad1 100644
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ b/packages/SystemUI/res/layout/recents_history_button.xml
@@ -15,15 +15,24 @@
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
- android:text="@string/recents_show_history_button_label"
+ android:paddingStart="14dp"
+ android:paddingEnd="14dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:text="@string/recents_history_button_label"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:textAllCaps="true"
+ android:drawableStart="@drawable/ic_history"
+ android:drawablePadding="6dp"
android:shadowColor="#99000000"
android:shadowDx="0"
android:shadowDy="2"
android:shadowRadius="5"
- android:fontFamily="sans-serif-medium" />
\ No newline at end of file
+ android:fontFamily="sans-serif-medium"
+ android:background="?android:selectableItemBackground"
+ android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
new file mode 100644
index 0000000..05f0979
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:paddingTop="14dp"
+ android:paddingBottom="14dp"
+ android:drawableStart="@drawable/recents_dismiss_all_history"
+ android:contentDescription="@string/recents_history_clear_all_button_label"
+ android:textSize="14sp"
+ android:textColor="#FFFFFF"
+ android:textAllCaps="true"
+ android:shadowColor="#99000000"
+ android:shadowDx="0"
+ android:shadowDy="2"
+ android:shadowRadius="5"
+ android:fontFamily="sans-serif-medium"
+ android:background="?android:selectableItemBackground"
+ android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_history_date.xml b/packages/SystemUI/res/layout/recents_history_date.xml
index 6d6a9ee..13c7dbe 100644
--- a/packages/SystemUI/res/layout/recents_history_date.xml
+++ b/packages/SystemUI/res/layout/recents_history_date.xml
@@ -15,10 +15,12 @@
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@android:style/Theme.Material"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="12dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
android:gravity="start"
android:textSize="14sp"
android:textColor="#009688"
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
index ae11006..e92c24a 100644
--- a/packages/SystemUI/res/layout/recents_history_task.xml
+++ b/packages/SystemUI/res/layout/recents_history_task.xml
@@ -15,7 +15,6 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@android:style/Theme.Material"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
@@ -27,7 +26,8 @@
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
- android:layout_marginStart="16dp" />
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="12dp" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
new file mode 100644
index 0000000..b4543bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.recents.tv.views.RecentsTvView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false" >
+
+ <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
+ android:id="@+id/task_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:descendantFocusability="beforeDescendants"
+ android:gravity="center"
+ android:paddingStart="@dimen/recents_tv_grid_row_padding"
+ android:paddingEnd="@dimen/recents_tv_grid_row_padding"
+ android:focusable="true"/>
+
+</com.android.systemui.recents.tv.views.RecentsTvView>
+
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
new file mode 100644
index 0000000..fa1daad
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_card_view.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true">
+
+ <RelativeLayout
+ android:layout_width="@dimen/recents_tv_card_width"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_gravity="center">
+ <ImageView
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/recents_tv_card_height"
+ android:scaleType="centerCrop"
+ android:gravity="center"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"/>
+
+ <RelativeLayout
+ android:id="@+id/card_info_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/card_view_thumbnail"
+ android:background="@color/recents_tv_card_background_color" >
+ <TextView
+ android:id="@+id/card_title_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="false"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_title_text_color"
+ android:ellipsize="end" />
+ <TextView
+ android:id="@+id/card_content_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/card_title_text"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_content_text_color"
+ android:ellipsize="end" />
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:scaleType="fitCenter"
+ android:background="@android:color/transparent"
+ android:contentDescription="@null"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
+ </RelativeLayout>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 5c67f80..deb8e91 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -49,8 +49,9 @@
android:layout_marginEnd="@dimen/recents_task_view_header_button_width"
android:layout_gravity="center_vertical|end"
android:padding="15dp"
- android:background="@drawable/recents_button_bg"
android:src="@drawable/star"
+ android:background="?android:selectableItemBackground"
+ android:alpha="0"
android:visibility="gone" />
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/dismiss_task"
@@ -58,9 +59,10 @@
android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_gravity="center_vertical|end"
android:padding="15dp"
- android:background="@drawable/recents_button_bg"
- android:visibility="invisible"
- android:src="@drawable/recents_dismiss_light" />
+ android:src="@drawable/recents_dismiss_light"
+ android:background="?android:selectableItemBackground"
+ android:alpha="0"
+ android:visibility="gone" />
<!-- The progress indicator shows if auto-paging is enabled -->
<ViewStub android:id="@+id/focus_timer_indicator_stub"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
index dabfc80..10659a3 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -45,6 +45,6 @@
android:layout_height="@dimen/recents_task_bar_height"
android:layout_gravity="center_vertical|end"
android:padding="15dp"
- android:background="@drawable/recents_button_bg"
+ android:background="?android:selectableItemBackground"
android:src="@drawable/recents_info_light" />
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/switch_bar.xml b/packages/SystemUI/res/layout/switch_bar.xml
new file mode 100644
index 0000000..f98de96
--- /dev/null
+++ b/packages/SystemUI/res/layout/switch_bar.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/switch_bar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="@drawable/switchbar_background"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:clickable="true"
+ android:gravity="center">
+
+ <TextView android:id="@+id/switch_text"
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:paddingStart="48dp"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:textAppearance="@android:style/TextAppearance.Material.Title"
+ android:textColor="?android:attr/textColorPrimaryInverse"
+ android:textAlignment="viewStart"
+ android:text="@string/switch_bar_on" />
+
+ <Switch
+ android:id="@android:id/switch_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@null"
+ android:theme="@style/ThemeOverlay.SwitchBar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 955efb5..19bc755 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -28,9 +28,6 @@
<declare-styleable name="NotificationLinearLayout">
<attr name="insetLeft" format="dimension" />
</declare-styleable>
- <declare-styleable name="NotificationRowLayout">
- <attr name="rowHeight" format="dimension" />
- </declare-styleable>
<declare-styleable name="RecentsPanelView">
<attr name="recentItemLayout" format="reference" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5e25d2c..9bb6dc6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,4 +151,12 @@
<color name="qs_tile_tint_unavailable">#40ffffff</color>
<color name="qs_tile_tint_inactive">#4dffffff</color>
<color name="qs_tile_tint_active">#ffffffff</color>
+
+ <color name="switch_bar_background">#ff37474f</color>
+ <color name="switch_accent_color">#ff7fcac3</color>
+
+ <!-- Keyboard shortcuts colors -->
+ <color name="ksh_system_group_color">#ff00bcd4</color>
+ <color name="ksh_application_group_color">#fff44336</color>
+ <color name="ksh_dialog_background_color">#ffffffff</color>
</resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
new file mode 100644
index 0000000..6f4c983
--- /dev/null
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="recents_tv_card_background_color">#FF37474F</color>
+ <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
+ <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
+ <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6df31ff..ebe0d97 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast
+ wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast,work
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e245c24..32d09e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -137,6 +137,8 @@
<dimen name="standard_notification_panel_width">416dp</dimen>
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
+ <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen>
+
<!-- Gravity for the notification panel -->
<integer name="standard_notification_panel_layout_gravity">0x31</integer><!-- top|center_horizontal -->
<integer name="notification_panel_layout_gravity">0x37</integer><!-- fill_horizontal|top -->
@@ -604,5 +606,4 @@
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
-
</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..77605bd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <!-- Dimens for recents card in the recents view on tv -->
+ <dimen name="recents_tv_card_width">150dip</dimen>
+ <dimen name="recents_tv_card_height">85dip</dimen>
+ <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+
+ <!-- Padding for grid view in recents view on tv -->
+ <dimen name="recents_tv_grid_row_padding">56dip</dimen>
+ <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
+ <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
+ <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+
+ <!-- Values for focus animation -->
+ <dimen name="recents_tv_unselected_item_z">6dp</dimen>
+ <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_button_bg.xml b/packages/SystemUI/res/values/integers_tv.xml
similarity index 78%
rename from packages/SystemUI/res/drawable/recents_button_bg.xml
rename to packages/SystemUI/res/values/integers_tv.xml
index 7456365..bfd8f8b 100644
--- a/packages/SystemUI/res/drawable/recents_button_bg.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#40ffffff">
-</ripple>
+<resources>
+ <integer name="item_scale_anim_duration">150</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 02158ac..32da3c6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -359,6 +359,9 @@
<!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_no_sim">No SIM.</string>
+ <!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_cell_data_off">Cellular Data Off</string>
+
<!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_bluetooth_tether">Bluetooth tethering.</string>
@@ -712,9 +715,9 @@
<!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
<string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
<!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
- <string name="recents_show_history_button_label">More</string>
- <!-- Recents: A format string to set the number of availabe historical tasks in recents. [CHAR LIMIT=NONE] -->
- <string name="recents_history_label_format"><xliff:g id="number">%d</xliff:g> More</string>
+ <string name="recents_history_button_label">History</string>
+ <!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
+ <string name="recents_history_clear_all_button_label">Clear</string>
<!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -1248,6 +1251,9 @@
<!-- Label for custom color transform [CHAR LIMIT=30] -->
<string name="color_matrix_custom">Custom colors</string>
+ <!-- Label for auto color transforms [CHAR LIMIT=30] -->
+ <string name="color_matrix_auto">Auto</string>
+
<!-- Label for unknown color transform [CHAR LIMIT=30] -->
<string name="color_matrix_unknown">Unknown colors</string>
@@ -1337,4 +1343,61 @@
<!-- Accessibility description for data saver being off [CHAR LIMIT=NONE] -->
<string name="accessibility_data_saver_off">Data Saver is off</string>
+ <!-- Label for feature switch [CHAR LIMIT=30] -->
+ <string name="switch_bar_on">On</string>
+
+ <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
+ <string name="nav_bar">Navigation bar</string>
+
+ <!-- SysUI Tuner: Group of buttons that show on the start of the screen [CHAR LIMIT=30] -->
+ <string name="start">Start</string>
+ <!-- SysUI Tuner: Group of buttons that show on the center of the screen [CHAR LIMIT=30] -->
+ <string name="center">Center</string>
+ <!-- SysUI Tuner: Group of buttons that show on the end of the screen [CHAR LIMIT=30] -->
+ <string name="end">End</string>
+ <!-- SysUI Tuner: Name of space used in custom navigation bar layouts [CHAR LIMIT=30] -->
+ <string name="space">Spacer</string>
+ <!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
+ <string name="menu_ime">Menu / Keyboard Switcher</string>
+ <!-- SysUI Tuner: Title for dialog to add a button [CHAR LIMIT=30] -->
+ <string name="select_button">Select button to add</string>
+ <!-- SysUI Tuner: Button to add a button [CHAR LIMIT=30] -->
+ <string name="add_button">Add button</string>
+ <!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
+ <string name="save">Save</string>
+ <!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
+ <string name="reset">Reset</string>
+
+ <!-- SysUI Tuner: Title of no home warning dialog [CHAR LIMIT=30] -->
+ <string name="no_home_title">No home button found</string>
+ <!-- SysUI Tuner: Message of no home warning dialog [CHAR LIMIT=NONE] -->
+ <string name="no_home_message">A home button is required to be able to navigate this device. Please add a home button before saving.</string>
+
+ <!-- SysUI Tuner: Adjust button width dialog title [CHAR LIMIT=60] -->
+ <string name="adjust_button_width">Adjust button width</string>
+
+ <!-- SysUI Tuner: Nav bar button that holds the clipboard [CHAR LIMIT=30] -->
+ <string name="clipboard">Clipboard</string>
+
+ <!-- SysUI Tuner: Description of nav bar button that holds the clipboard [CHAR LIMIT=NONE] -->
+ <string name="clipboard_description">The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present.</string>
+
+ <!-- SysUI Tuner: Accessibility description for custom nav key [CHAR LIMIT=NONE] -->
+ <string name="accessibility_key">Custom navigation button</string>
+
+ <!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
+ <string name="keycode">Keycode</string>
+
+ <!-- SysUI Tuner: Description of nav bar button that emulates a keycode [CHAR LIMIT=NONE] -->
+ <string name="keycode_description">Keycode buttons allow keyboard keys to
+ be added to the Navigation Bar. When pressed they emulate the selected
+ keyboard key. First the key must be selected for the button, followed
+ by an image to be shown on the button.</string>
+
+ <!-- SysUI Tuner: Title of dialog to select which key to emulate [CHAR LIMIT=60] -->
+ <string name="select_keycode">Select Keyboard Button</string>
+
+ <!-- SysUI Tuner: Label for preview area in navigation bar tuner [CHAR LIMIT=NONE] -->
+ <string name="preview">Preview</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index d432a62..c64327d 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -18,15 +18,15 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Button to close PIP on PIP UI -->
- <string name="pip_exit">Close PIP</string>
+ <string name="pip_exit" translatable="false">Close PIP</string>
<!-- Button to move PIP screen to the fullscreen on PIP UI -->
- <string name="pip_fullscreen">Full screen</string>
+ <string name="pip_fullscreen" translatable="false">Full screen</string>
<!-- Button to play the current media on PIP UI -->
- <string name="pip_play">Play</string>
+ <string name="pip_play" translatable="false">Play</string>
<!-- Button to pause the current media on PIP UI -->
- <string name="pip_pause">Pause</string>
+ <string name="pip_pause" translatable="false">Pause</string>
<!-- Button to close PIP overlay menu on PIP UI -->
- <string name="pip_cancel">Cancel</string>
+ <string name="pip_cancel" translatable="false">Cancel</string>
<!-- Overlay text on PIP -->
- <string name="pip_hold_home">Hold HOME to control PIP</string>
+ <string name="pip_hold_home" translatable="false">Hold HOME to control PIP</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4329f78..9931ab9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -20,7 +20,7 @@
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
</style>
- <style name="RecentsTheme" parent="@android:style/Theme.Material.Light">
+ <style name="RecentsTheme" parent="@android:style/Theme.Material">
<!-- NoTitle -->
<item name="android:windowNoTitle">true</item>
<!-- Misc -->
@@ -310,6 +310,7 @@
</style>
<style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
+ <item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
</style>
@@ -345,4 +346,8 @@
<item name="android:textColor">@*android:color/material_deep_teal_500</item>
</style>
+ <style name="ThemeOverlay.SwitchBar" parent="@android:style/ThemeOverlay">
+ <item name="android:colorAccent">@color/switch_accent_color</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
new file mode 100644
index 0000000..45cdc07
--- /dev/null
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <item format="float" type="raw" name="unselected_scale">1.0</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 67a7a23..febe518 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -166,6 +166,11 @@
</PreferenceScreen>
+ <Preference
+ android:key="nav_bar"
+ android:title="@string/nav_bar"
+ android:fragment="com.android.systemui.tuner.NavBarTuner" />
+
<!-- Warning, this goes last. -->
<Preference
android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 38ae345..a0dbad4 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -22,12 +22,19 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
-import android.graphics.*;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
+
import com.android.systemui.statusbar.policy.BatteryController;
public class BatteryMeterDrawable extends Drawable implements DemoMode,
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index b4f63eb..0bf81e9 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
+
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
index fc98ec4..f8ce1d3 100644
--- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -18,7 +18,6 @@
import android.os.Handler;
import android.os.Looper;
-import android.os.StrictMode;
import android.view.Choreographer;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
index 14392b4..5e96379 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
@@ -22,7 +22,14 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.*;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index ec19e5a..9a64a41 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -16,8 +16,6 @@
package com.android.systemui;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-
import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.content.BroadcastReceiver;
@@ -34,6 +32,8 @@
import android.util.Log;
import android.view.WindowManagerGlobal;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
/**
* Manages notification when a guest session is resumed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 5a6f3c9..1306284 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -17,6 +17,7 @@
package com.android.systemui;
import static android.opengl.GLES20.*;
+
import static javax.microedition.khronos.egl.EGL10.*;
import android.app.ActivityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
rename to packages/SystemUI/src/com/android/systemui/Interpolators.java
index 5979468..cd6dce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -14,9 +14,10 @@
* limitations under the License
*/
-package com.android.systemui.statusbar;
+package com.android.systemui;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
@@ -32,4 +33,5 @@
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
public static final Interpolator LINEAR = new LinearInterpolator();
public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+ public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 5b955a4..33b43fe 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -32,7 +32,6 @@
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.Interpolators;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
@@ -67,6 +66,7 @@
private FalsingManager mFalsingManager;
private float mInitialTouchPos;
+ private float mPerpendicularInitialTouchPos;
private boolean mDragging;
private View mCurrView;
private View mCurrAnimView;
@@ -117,6 +117,10 @@
return mSwipeDirection == X ? ev.getX() : ev.getY();
}
+ private float getPerpendicularPos(MotionEvent ev) {
+ return mSwipeDirection == X ? ev.getY() : ev.getX();
+ }
+
private float getTranslation(View v) {
return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
}
@@ -240,6 +244,7 @@
mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
mVelocityTracker.addMovement(ev);
mInitialTouchPos = getPos(ev);
+ mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
if (mLongPressListener != null) {
if (mWatchLongPress == null) {
@@ -271,8 +276,11 @@
if (mCurrView != null && !mLongPressSent) {
mVelocityTracker.addMovement(ev);
float pos = getPos(ev);
+ float perpendicularPos = getPerpendicularPos(ev);
float delta = pos - mInitialTouchPos;
- if (Math.abs(delta) > mPagingTouchSlop) {
+ float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
+ if (Math.abs(delta) > mPagingTouchSlop
+ && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
mCallback.onBeginDrag(mCurrView);
mDragging = true;
mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
@@ -280,7 +288,6 @@
removeLongPressCallback();
}
}
-
break;
case MotionEvent.ACTION_UP:
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index 25f8bb0..2c96e31 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -25,8 +25,6 @@
import android.graphics.Paint;
import android.view.View;
-import com.android.systemui.statusbar.Interpolators;
-
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index 0e28002..faaad2b 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -23,9 +23,9 @@
import java.util.ArrayList;
import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
/**
* Collects touch, sensor and phone events and converts the data to
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index 92cd027..5878219 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -33,8 +33,8 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
/**
* Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
index 34770c4..f78436a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
@@ -22,8 +22,8 @@
import android.view.View;
import android.widget.FrameLayout;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class AssistOrbContainer extends FrameLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
index 2d933f6..abcf27d 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
@@ -32,8 +32,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class AssistOrbView extends FrameLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index a6ebc0b..dba731a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -18,8 +18,6 @@
import android.view.MotionEvent;
-import java.lang.Math;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 27d4c0e..7ddbdf0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.SensorEvent;
-import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
@@ -35,6 +34,10 @@
public class HumanInteractionClassifier extends Classifier {
private static final String HIC_ENABLE = "HIC_enable";
private static final float FINGER_DISTANCE = 0.1f;
+
+ /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
+ private static final int HIC_ENABLE_DEFAULT = 1;
+
private static HumanInteractionClassifier sInstance = null;
private final Handler mHandler = new Handler();
@@ -101,9 +104,9 @@
}
private void updateConfiguration() {
- mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+ mEnableClassifier = 0 != Settings.Global.getInt(
mContext.getContentResolver(),
- HIC_ENABLE, 0);
+ HIC_ENABLE, HIC_ENABLE_DEFAULT);
}
public void setType(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index d544a3d..d58274d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -18,8 +18,6 @@
import android.view.MotionEvent;
-import java.lang.Math;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLand.java b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
index b84777b..0fb4432 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/MLand.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
@@ -48,12 +48,11 @@
import android.widget.ImageView;
import android.widget.TextView;
-import java.util.ArrayList;
-
import com.android.internal.logging.MetricsLogger;
-
import com.android.systemui.R;
+import java.util.ArrayList;
+
// It's like LLand, but "M"ultiplayer.
public class MLand extends FrameLayout {
public static final String TAG = "MLand";
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
index 64f3e13f..5deea9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
@@ -16,11 +16,9 @@
package com.android.systemui.keyboard;
-import android.app.AlertDialog;
import android.content.Context;
import android.view.WindowManager;
-import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
public class BluetoothDialog extends SystemUIDialog {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 481b9180..ea7270d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -16,10 +16,8 @@
package com.android.systemui.keyboard;
-import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
@@ -29,7 +27,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.res.Configuration;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -42,7 +39,6 @@
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Slog;
-import android.view.WindowManager;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -58,7 +54,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Set;
public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0475c72..958572f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -24,7 +24,6 @@
import android.app.SearchManager;
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
-import android.auditing.SecurityLog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -1371,10 +1370,8 @@
* @see #KEYGUARD_DONE
*/
private void handleKeyguardDone(boolean authenticated) {
- if (SecurityLog.isLoggingEnabled()
- && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_UNLOCK_ATTEMPT,
- (authenticated ? 1 : 0), "Unknown");
+ if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed();
}
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
synchronized (this) {
@@ -1487,9 +1484,8 @@
* @see #SHOW
*/
private void handleShow(Bundle options) {
- if (SecurityLog.isLoggingEnabled()
- && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- SecurityLog.writeEvent(SecurityLog.TAG_DEVICE_LOCKED, "");
+ if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured();
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index adc9b36..b2a80f4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -23,24 +23,23 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
-import android.media.projection.MediaProjectionManager;
-import android.media.projection.IMediaProjectionManager;
import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.BidiFormatter;
-import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
-import android.util.TypedValue;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
+
import com.android.systemui.R;
public class MediaProjectionPermissionActivity extends Activity
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index b3c0783..f201165 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -16,11 +16,6 @@
package com.android.systemui.net;
-import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -37,6 +32,11 @@
import com.android.systemui.R;
+import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
+import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
+import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+
/**
* Notify user that a {@link NetworkTemplate} is over its
* {@link NetworkPolicy#limitBytes}, giving them the choice of acknowledging or
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 6bc8b50..d723367 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,6 +6,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
index 699273a..a1c2577 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -16,8 +16,6 @@
package com.android.systemui.qs;
-import com.android.systemui.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -26,6 +24,8 @@
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import com.android.systemui.R;
+
import java.lang.ref.WeakReference;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 7651ae8..ed90904 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+
import com.android.systemui.R;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 72629a3..35000d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -23,7 +24,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -35,6 +35,7 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DisplayController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -82,9 +83,8 @@
/**
* Declare the category of this tile.
*
- * Categories are defined in {@link com.android.internal.logging.MetricsLogger}
- * or if there is no relevant existing category you may define one in
- * {@link com.android.systemui.qs.QSTile}.
+ * Categories are defined in {@link com.android.internal.logging.MetricsProto.MetricsEvent}
+ * by editing frameworks/base/proto/src/metrics_constants.proto.
*/
abstract public int getMetricsCategory();
@@ -271,7 +271,7 @@
protected void checkIfRestrictionEnforced(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- userRestriction, UserHandle.myUserId());
+ userRestriction, ActivityManager.getCurrentUser());
if (admin != null) {
state.disabledByPolicy = true;
state.enforcedAdmin = admin;
@@ -390,6 +390,7 @@
UserInfoController getUserInfoController();
BatteryController getBatteryController();
TileServices getTileServices();
+ DisplayController getDisplayController();
void removeTile(String tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 68461f5..1a854c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -24,6 +24,7 @@
import android.os.Message;
import android.view.View;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
public class QSTileBaseView extends LinearLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 664ca39..0d5d115 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index b391c1e..753efb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 59a394f..f7e2338 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -5,6 +5,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
index ac4f05f..36bed0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
@@ -20,7 +20,9 @@
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -84,6 +86,6 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_INTENT;
+ return MetricsEvent.QS_INTENT;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index eab4dca..02cb0cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -27,6 +27,7 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 8f0d194..98c7be4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.qs.PagedTileLayout;
import com.android.systemui.qs.PagedTileLayout.TilePage;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index cc4ce70..a6c7fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -37,6 +37,7 @@
import android.widget.ListView;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTile.Host.Callback;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 8ae2d7b..a4d7e93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -37,6 +37,7 @@
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.Icon;
@@ -72,8 +73,9 @@
}
mCurrentTiles = tileSpecs;
final TileGroup group = new TileGroup("com.android.settings", mContext);
+ boolean hasColorMod = host.getDisplayController().isEnabled();
String possible = mContext.getString(R.string.quick_settings_tiles_default)
- + ",hotspot,inversion,saver";
+ + ",hotspot,inversion,saver" + (hasColorMod ? ",colors" : "");
String[] possibleTiles = possible.split(",");
for (int i = 0; i < possibleTiles.length; i++) {
final String spec = possibleTiles[i];
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index d398b64..886531a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -31,7 +31,9 @@
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.phone.QSTileHost;
@@ -197,7 +199,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_CUSTOM;
+ return MetricsEvent.QS_CUSTOM;
}
public void startUnlockAndRun() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 4977d80..c4436f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.qs.external;
+import libcore.util.Objects;
+
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -35,7 +37,6 @@
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
-import libcore.util.Objects;
import java.util.Set;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 44d8776..04391fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -33,6 +33,7 @@
import android.service.quicksettings.TileService;
import android.util.ArrayMap;
import android.util.Log;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.StatusBarIconController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index c696f88..d78d6ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -24,6 +24,7 @@
import android.provider.Settings.Global;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.qs.QSTile;
@@ -85,7 +86,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_AIRPLANEMODE;
+ return MetricsEvent.QS_AIRPLANEMODE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 60238fc3..64b3a6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -25,7 +25,8 @@
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.logging.MetricsLogger;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.BatteryInfo;
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.R;
@@ -64,7 +65,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_BATTERY_TILE;
+ return MetricsEvent.QS_BATTERY_TILE;
}
@Override
@@ -199,7 +200,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_BATTERY_DETAIL;
+ return MetricsEvent.QS_BATTERY_DETAIL;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 3750290..dbb7423 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -24,7 +24,9 @@
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
@@ -76,6 +78,10 @@
@Override
protected void handleClick() {
+ if (!mController.canConfigBluetooth()) {
+ mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+ return;
+ }
if (!mState.value) {
mState.value = true;
mController.setBluetoothEnabled(true);
@@ -127,7 +133,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_BLUETOOTH;
+ return MetricsEvent.QS_BLUETOOTH;
}
@Override
@@ -181,14 +187,14 @@
@Override
public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state);
+ MetricsLogger.action(mContext, MetricsEvent.QS_BLUETOOTH_TOGGLE, state);
mController.setBluetoothEnabled(state);
showDetail(false);
}
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_BLUETOOTH_DETAILS;
+ return MetricsEvent.QS_BLUETOOTH_DETAILS;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index de4c21c..18eb7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -23,7 +23,9 @@
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
@@ -125,7 +127,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_CAST;
+ return MetricsEvent.QS_CAST;
}
@Override
@@ -181,7 +183,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_CAST_DETAILS;
+ return MetricsEvent.QS_CAST_DETAILS;
}
@Override
@@ -255,7 +257,7 @@
@Override
public void onDetailItemClick(Item item) {
if (item == null || item.tag == null) return;
- MetricsLogger.action(mContext, MetricsLogger.QS_CAST_SELECT);
+ MetricsLogger.action(mContext, MetricsEvent.QS_CAST_SELECT);
final CastDevice device = (CastDevice) item.tag;
mController.startCasting(device);
}
@@ -263,7 +265,7 @@
@Override
public void onDetailItemDisconnect(Item item) {
if (item == null || item.tag == null) return;
- MetricsLogger.action(mContext, MetricsLogger.QS_CAST_DISCONNECT);
+ MetricsLogger.action(mContext, MetricsEvent.QS_CAST_DISCONNECT);
final CastDevice device = (CastDevice) item.tag;
mController.stopCasting(device);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1f8fae0..aacdbc9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -23,7 +23,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
import com.android.systemui.qs.QSIconView;
@@ -89,7 +91,7 @@
protected void handleSecondaryClick() {
boolean dataEnabled = mDataController.isMobileDataSupported()
&& mDataController.isMobileDataEnabled();
- MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, !dataEnabled);
+ MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, !dataEnabled);
mDataController.setMobileDataEnabled(!dataEnabled);
}
@@ -131,7 +133,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_CELLULAR;
+ return MetricsEvent.QS_CELLULAR;
}
// Remove the period from the network name
@@ -241,13 +243,13 @@
@Override
public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, state);
+ MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, state);
mDataController.setMobileDataEnabled(state);
}
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_DATAUSAGEDETAIL;
+ return MetricsEvent.QS_DATAUSAGEDETAIL;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 23a15b9..6e843e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -17,7 +17,9 @@
package com.android.systemui.qs.tiles;
import android.provider.Settings.Secure;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.SecureSetting;
@@ -84,7 +86,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_COLORINVERSION;
+ return MetricsEvent.QS_COLORINVERSION;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index 2be43c0..bad4e79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 39eda6b..f99a3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,11 +29,11 @@
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
-import android.widget.Toast;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SysUIToast;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
@@ -154,7 +154,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_DND;
+ return MetricsEvent.QS_DND;
}
@Override
@@ -229,7 +229,7 @@
@Override
public void setToggleState(boolean state) {
- MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state);
+ MetricsLogger.action(mContext, MetricsEvent.QS_DND_TOGGLE, state);
if (!state) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
showDetail(false);
@@ -238,7 +238,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_DND_DETAILS;
+ return MetricsEvent.QS_DND_DETAILS;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 39d9da1..1d9f15b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -17,7 +17,9 @@
package com.android.systemui.qs.tiles;
import android.app.ActivityManager;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -92,7 +94,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_FLASHLIGHT;
+ return MetricsEvent.QS_FLASHLIGHT;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 55aa32b..2f37943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,7 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -65,6 +68,8 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+ state.disabledByPolicy = mController.isTetheringAllowed();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
@@ -75,7 +80,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_HOTSPOT;
+ return MetricsEvent.QS_HOTSPOT;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 0883445..e1dc9f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -30,6 +30,7 @@
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.qs.QSTile;
import java.util.Arrays;
@@ -155,7 +156,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_INTENT;
+ return MetricsEvent.QS_INTENT;
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index e79aabf..8328897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,7 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -84,6 +87,8 @@
// bug is fixed, this should be reverted to only hiding it on secure lock screens:
// state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
state.value = locationEnabled;
+ state.disabledByPolicy = mController.isUserLocationRestricted();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
if (locationEnabled) {
state.icon = mEnable;
state.label = mContext.getString(R.string.quick_settings_location_label);
@@ -99,7 +104,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_LOCATION;
+ return MetricsEvent.QS_LOCATION;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 79155b2..f920d48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -18,7 +18,9 @@
import android.content.Context;
import android.content.res.Configuration;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -108,7 +110,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_ROTATIONLOCK;
+ return MetricsEvent.QS_ROTATIONLOCK;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 167c611..33befd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -16,11 +16,6 @@
package com.android.systemui.qs.tiles;
-import com.android.internal.util.ArrayUtils;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.UserAvatarView;
-
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -34,6 +29,11 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.util.ArrayUtils;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.UserAvatarView;
+
/**
* Displays one user in the {@link UserDetailView} view.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index b44ef0b..2c8a478 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -24,6 +24,7 @@
import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
@@ -94,7 +95,7 @@
mContext, tag.enforcedAdmin);
mController.startActivity(intent);
} else {
- MetricsLogger.action(mContext, MetricsLogger.QS_SWITCH_USER);
+ MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
switchTo(tag);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index d29cae4..1565b6f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -18,7 +18,8 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Pair;
-import com.android.internal.logging.MetricsLogger;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -52,7 +53,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_USER_TILE;
+ return MetricsEvent.QS_USER_TILE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 95ea3f8..42296f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -24,7 +24,9 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
@@ -162,7 +164,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_WIFI;
+ return MetricsEvent.QS_WIFI;
}
@Override
@@ -256,14 +258,14 @@
@Override
public void setToggleState(boolean state) {
if (DEBUG) Log.d(TAG, "setToggleState " + state);
- MetricsLogger.action(mContext, MetricsLogger.QS_WIFI_TOGGLE, state);
+ MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
mController.setWifiEnabled(state);
showDetail(false);
}
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_WIFI_DETAILS;
+ return MetricsEvent.QS_WIFI_DETAILS;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 34ed37b..508490f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -24,7 +24,9 @@
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -124,7 +126,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_WORKMODE;
+ return MetricsEvent.QS_WORKMODE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index b8310f2..e4fd31d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -34,6 +34,7 @@
import android.util.Log;
import android.view.Display;
import android.view.View;
+
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 189e8d3..c3b794d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -34,10 +34,11 @@
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
@@ -68,7 +69,6 @@
import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
-import com.android.systemui.recents.history.RecentsHistoryView;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -80,8 +80,6 @@
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.statusbar.BaseStatusBar;
-import java.util.ArrayList;
-
/**
* The main Recents activity that is started from AlternateRecentsComponent.
*/
@@ -103,8 +101,6 @@
// Top level views
private RecentsView mRecentsView;
private SystemBarScrimViews mScrimViews;
- private ViewStub mHistoryViewStub;
- private RecentsHistoryView mHistoryView;
// Search AppWidget
private AppWidgetProviderInfo mSearchWidgetInfo;
@@ -125,12 +121,14 @@
* just finishing the activity since we don't know what is behind Recents in the task stack.
*/
class FinishRecentsRunnable implements Runnable {
+
Intent mLaunchIntent;
+ ActivityOptions mOpts;
/**
* Creates a finish runnable that starts the specified intent.
*/
- public FinishRecentsRunnable(Intent launchIntent) {
+ public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
mLaunchIntent = launchIntent;
}
@@ -139,13 +137,16 @@
try {
RecentsActivityLaunchState launchState =
Recents.getConfiguration().getLaunchState();
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_enter :
- R.anim.recents_to_launcher_enter,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_exit :
- R.anim.recents_to_launcher_exit);
+ ActivityOptions opts = mOpts;
+ if (opts == null) {
+ opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_enter :
+ R.anim.recents_to_launcher_enter,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_exit :
+ R.anim.recents_to_launcher_exit);
+ }
startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
} catch (Exception e) {
Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
@@ -203,12 +204,9 @@
int launchTaskIndexInStack = launchTarget != null
? stack.indexOfStackTask(launchTarget)
: 0;
- boolean hasStatusBarScrim = taskCount > 0;
- boolean animateStatusBarScrim = launchState.launchedFromHome;
boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
boolean animateNavBarScrim = true;
- mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim,
- hasNavBarScrim, animateNavBarScrim);
+ mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
// Keep track of whether we launched from the nav bar button or via alt-tab
if (launchState.launchedWithAltTab) {
@@ -232,8 +230,7 @@
* Dismisses the history view back into the stack view.
*/
boolean dismissHistory() {
- // Try and hide the history view first
- if (mHistoryView != null && mHistoryView.isVisible()) {
+ if (mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
return true;
}
@@ -285,9 +282,24 @@
* Dismisses Recents directly to Home without checking whether it is currently visible.
*/
void dismissRecentsToHome(boolean animateTaskViews) {
+ dismissRecentsToHome(animateTaskViews, null);
+ }
+
+ /**
+ * Dismisses Recents directly to Home without checking whether it is currently visible.
+ *
+ * @param overrideAnimation If not null, will override the default animation that is based on
+ * how Recents was launched.
+ */
+ void dismissRecentsToHome(boolean animateTaskViews, ActivityOptions overrideAnimation) {
DismissRecentsToHomeAnimationStarted dismissEvent =
new DismissRecentsToHomeAnimationStarted(animateTaskViews);
- dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+ if (overrideAnimation != null) {
+ dismissEvent.addPostAnimationCallback(new FinishRecentsRunnable(
+ mFinishLaunchHomeRunnable.mLaunchIntent, overrideAnimation));
+ } else {
+ dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+ }
dismissEvent.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
@@ -340,7 +352,6 @@
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- mHistoryViewStub = (ViewStub) findViewById(R.id.history_view_stub);
mScrimViews = new SystemBarScrimViews(this);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -358,7 +369,7 @@
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+ mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, null);
// Bind the search app widget when we first start up
if (RecentsDebugFlags.Static.EnableSearchBar) {
@@ -402,7 +413,7 @@
SystemServicesProxy ssp = Recents.getSystemServices();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
- MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
+ MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
mRecentsView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@@ -439,7 +450,7 @@
// Reset some states
mIgnoreAltTabRelease = false;
- if (mHistoryView != null) {
+ if (mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
}
@@ -460,7 +471,7 @@
launchState.launchedHasConfigurationChanged = false;
launchState.launchedViaDragGesture = false;
- MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
+ MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
}
@Override
@@ -501,8 +512,7 @@
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE,
- (mHistoryView != null) && mHistoryView.isVisible());
+ outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
}
@Override
@@ -633,7 +643,7 @@
// Focus the next task
EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
- MetricsLogger.action(this, MetricsLogger.ACTION_OVERVIEW_PAGE);
+ MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
}
}
@@ -649,15 +659,12 @@
}
} else if (event.triggeredFromHomeKey) {
// Otherwise, dismiss Recents to Home
- if (mHistoryView != null && mHistoryView.isVisible()) {
- HideHistoryEvent hideEvent = new HideHistoryEvent(true /* animate */);
- hideEvent.addPostAnimationCallback(new Runnable() {
- @Override
- public void run() {
- dismissRecentsToHome(true /* animateTaskViews */);
- }
- });
- EventBus.getDefault().send(hideEvent);
+ if (mRecentsView.isHistoryVisible()) {
+ // If the history view is visible, then just cross-fade home
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
+ R.anim.recents_to_launcher_enter,
+ R.anim.recents_to_launcher_exit);
+ dismissRecentsToHome(false /* animate */, opts);
} else {
dismissRecentsToHome(true /* animateTaskViews */);
@@ -793,21 +800,6 @@
mIgnoreAltTabRelease = true;
}
- public final void onBusEvent(ShowHistoryEvent event) {
- if (mHistoryView == null) {
- mHistoryView = (RecentsHistoryView) mHistoryViewStub.inflate();
- // Since this history view is inflated by a view stub after the insets have already
- // been applied, we have to set them ourselves initial from the insets that were last
- // provided.
- mHistoryView.setSystemInsets(mRecentsView.getSystemInsets());
- }
- mHistoryView.show(mRecentsView.getTaskStack(), event.getAnimationTrigger());
- }
-
- public final void onBusEvent(HideHistoryEvent event) {
- mHistoryView.hide(event.animate, event.getAnimationTrigger());
- }
-
private void refreshSearchWidgetView() {
if (mSearchWidgetInfo != null) {
SystemServicesProxy ssp = Recents.getSystemServices();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 573db98..318c69f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -20,6 +20,7 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 61780f8..0115f91 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 49f2ab0..6b8968f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b78fd22..5a60a19 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,10 +19,12 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
+import android.app.UiModeManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -36,6 +38,7 @@
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -87,7 +90,10 @@
public final static String RECENTS_PACKAGE = "com.android.systemui";
public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
+ public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity";
+ //Used to store tv or non-tv activty for use in creating intents.
+ private final String mRecentsIntentActivityName;
/**
* An implementation of ITaskStackListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
@@ -210,6 +216,14 @@
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
launchOpts.onlyLoadForCache = true;
loader.loadTasks(mContext, plan, launchOpts);
+
+ //Manager used to determine if we are running on tv or not
+ UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
+ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+ mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
+ } else {
+ mRecentsIntentActivityName = RECENTS_ACTIVITY;
+ }
}
public void onBootCompleted() {
@@ -792,7 +806,7 @@
} else {
Canvas c = new Canvas(thumbnail);
c.scale(toTransform.scale, toTransform.scale);
- mHeaderBar.rebindToTask(toTask);
+ mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */);
mHeaderBar.draw(c);
c.setBitmap(null);
}
@@ -906,10 +920,11 @@
launchState.launchedViaDragGesture = mDraggingInRecents;
Intent intent = new Intent();
- intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+ intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
index 39d0d59..2c1158d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
+
import com.android.systemui.SystemUIApplication;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 10075bc..13d4acb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -39,6 +39,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.systemui.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index 212c7f4..0d56ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.util.Log;
import android.util.MutableBoolean;
+
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import java.lang.ref.WeakReference;
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
similarity index 60%
copy from location/java/android/location/IGpsStatusProvider.aidl
copy to packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
index cf277c8..98c0a69 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.location;
+package com.android.systemui.recents.events.activity;
-import android.location.IGpsStatusListener;
+import com.android.systemui.recents.events.EventBus;
/**
- * An interface for location providers that provide GPS status information.
- *
- * {@hide}
+ * This is sent when the history is to be cleared
*/
-interface IGpsStatusProvider {
- void addGpsStatusListener(IGpsStatusListener listener);
- void removeGpsStatusListener(IGpsStatusListener listener);
+public class ClearHistoryEvent extends EventBus.AnimatedEvent {
+ // Simple event
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
index af3eeb0..bacf3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
@@ -21,7 +21,7 @@
/**
* This is sent when the history view will be closed.
*/
-public class HideHistoryEvent extends EventBus.AnimatedEvent {
+public class HideHistoryEvent extends EventBus.Event {
public final boolean animate;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 21b9301..3db106e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.activity;
import android.graphics.Rect;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
index 7042537..ae803ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
@@ -22,5 +22,11 @@
* This is sent when the history view button should be shown.
*/
public class ShowHistoryButtonEvent extends EventBus.Event {
- // Simple event
+
+ // Whether or not to translate the history button when showing it
+ public final boolean translate;
+
+ public ShowHistoryButtonEvent(boolean translate) {
+ this.translate = translate;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
index b39d645..469f336 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
@@ -21,7 +21,7 @@
/**
* This is sent when the history view button is clicked.
*/
-public class ShowHistoryEvent extends EventBus.AnimatedEvent {
+public class ShowHistoryEvent extends EventBus.Event {
// Simple event
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index 7579cd8..f87f6de 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -22,7 +22,7 @@
/**
* This is sent by the activity whenever the task stach has changed.
*/
-public class TaskStackUpdatedEvent extends EventBus.Event {
+public class TaskStackUpdatedEvent extends EventBus.AnimatedEvent {
/**
* A new TaskStack instance representing the latest stack state.
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
similarity index 60%
copy from location/java/android/location/IGpsStatusProvider.aidl
copy to packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
index cf277c8..aaf77af 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-package android.location;
+package com.android.systemui.recents.events.activity;
-import android.location.IGpsStatusListener;
+import com.android.systemui.recents.events.EventBus;
/**
- * An interface for location providers that provide GPS status information.
- *
- * {@hide}
+ * This is sent when the history view button is clicked.
*/
-interface IGpsStatusProvider {
- void addGpsStatusListener(IGpsStatusListener listener);
- void removeGpsStatusListener(IGpsStatusListener listener);
+public class ToggleHistoryEvent extends EventBus.AnimatedEvent {
+
+ // Simple event
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
index 898d1fc..4140bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.component;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
index f9ccfc8..75e459a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.component;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
/**
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
similarity index 60%
copy from location/java/android/location/IGpsStatusProvider.aidl
copy to packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
index cf277c8..863f40b 100644
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.location;
+package com.android.systemui.recents.events.ui;
-import android.location.IGpsStatusListener;
+import com.android.systemui.recents.events.EventBus;
/**
- * An interface for location providers that provide GPS status information.
- *
- * {@hide}
+ * This is sent to reset the background scrim back to the initial state.
*/
-interface IGpsStatusProvider {
- void addGpsStatusListener(IGpsStatusListener listener);
- void removeGpsStatusListener(IGpsStatusListener listener);
+public class ResetBackgroundScrimEvent extends EventBus.Event {
+ // Simple event
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
index ad9feb6..c4b47c0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.ui;
import android.util.MutableInt;
+
import com.android.systemui.recents.events.EventBus;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
new file mode 100644
index 0000000..fdd4c67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent to request an update to the background scrim.
+ */
+public class UpdateBackgroundScrimEvent extends EventBus.Event {
+
+ public final float alpha;
+
+ public UpdateBackgroundScrimEvent(float alpha) {
+ this.alpha = alpha;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index b81c10c..b368bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.ui.dragndrop;
import android.graphics.Point;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
index b450b1f..7030729 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
@@ -19,6 +19,7 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.RecentsViewTouchHandler;
+import com.android.systemui.recents.views.TaskView;
/**
* This event is sent by the drag manager when it requires drop targets to register themselves for
@@ -27,10 +28,13 @@
public class DragStartInitializeDropTargetsEvent extends EventBus.Event {
public final Task task;
+ public final TaskView taskView;
public final RecentsViewTouchHandler handler;
- public DragStartInitializeDropTargetsEvent(Task task, RecentsViewTouchHandler handler) {
+ public DragStartInitializeDropTargetsEvent(Task task, TaskView taskView,
+ RecentsViewTouchHandler handler) {
this.task = task;
+ this.taskView = taskView;
this.handler = handler;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index f6655c7..e288878 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -26,12 +26,15 @@
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -74,6 +77,10 @@
// This callback is only made for TaskRow view holders
ImageView iv = (ImageView) content.findViewById(R.id.icon);
iv.setImageDrawable(task.icon);
+ iv.animate()
+ .alpha(1f)
+ .setDuration(100)
+ .start();
}
@Override
@@ -81,6 +88,7 @@
// This callback is only made for TaskRow view holders
ImageView iv = (ImageView) content.findViewById(R.id.icon);
iv.setImageBitmap(null);
+ iv.animate().cancel();
}
@Override
@@ -132,7 +140,7 @@
ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
ActivityOptions.makeBasic());
- MetricsLogger.action(v.getContext(), MetricsLogger.ACTION_OVERVIEW_SELECT,
+ MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
task.key.getComponent().toString());
}
@@ -164,14 +172,16 @@
final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
Collections.reverse(tasksMostRecent);
int prevDateKey = -1;
+ int taskCount = tasksMostRecent.size();
mRows.clear();
mTaskRowCount.clear();
- for (Task task : tasksMostRecent) {
+ Calendar cal = Calendar.getInstance(l);
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasksMostRecent.get(i);
if (task.isFreeformTask()) {
continue;
}
- Calendar cal = Calendar.getInstance(l);
cal.setTimeInMillis(task.key.lastActiveTime);
int dateKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
if (dateKey != prevDateKey) {
@@ -206,6 +216,23 @@
}
/**
+ * Removes all historical tasks.
+ */
+ public void removeAllTasks() {
+ for (int i = mRows.size() - 1; i >= 0; i--) {
+ Row row = mRows.get(i);
+ if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
+ TaskRow taskRow = (TaskRow) row;
+ Task task = taskRow.task;
+ mStack.removeTask(task, TaskViewAnimation.IMMEDIATE);
+ EventBus.getDefault().send(new DeleteTaskDataEvent(task));
+ i = removeTaskRow(i);
+ }
+ }
+ dismissHistory();
+ }
+
+ /**
* Returns the row at the given {@param position}.
*/
public Row getRow(int position) {
@@ -243,8 +270,10 @@
taskRow.task.addCallback(holder);
TextView tv = (TextView) holder.content.findViewById(R.id.description);
tv.setText(taskRow.task.title);
+ ImageView iv = (ImageView) holder.content.findViewById(R.id.icon);
+ iv.setAlpha(0f);
holder.content.setOnClickListener(taskRow);
- loader.loadTaskData(taskRow.task);
+ loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */);
break;
}
}
@@ -253,19 +282,25 @@
@Override
public void onViewRecycled(ViewHolder holder) {
RecentsTaskLoader loader = Recents.getTaskLoader();
-
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Row row = mRows.get(position);
int viewType = row.getViewType();
if (viewType == TASK_ROW_VIEW_TYPE) {
TaskRow taskRow = (TaskRow) row;
- taskRow.task.removeCallback(holder);
loader.unloadTaskData(taskRow.task);
+ taskRow.task.removeCallback(holder);
}
}
}
+ @Override
+ public boolean onFailedToRecycleView(ViewHolder holder) {
+ // Always recycle views, even if it is animating
+ onViewRecycled(holder);
+ return true;
+ }
+
public void onTaskRemoved(Task task, int position) {
// Since this is removed from the history, we need to update the stack as well to ensure
// that the model is correct. Since the stack is hidden, we can update it immediately.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
index a91ea7e..acad0ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 39bb6ca..843adc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents.history;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -25,35 +26,40 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.LinearLayout;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.ClearHistoryEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
+import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.AnimateableViewBounds;
/**
* A list of the recent tasks that are not in the stack.
*/
-public class RecentsHistoryView extends LinearLayout {
+public class RecentsHistoryView extends LinearLayout
+ implements ValueAnimator.AnimatorUpdateListener {
- private static final String TAG = "RecentsHistoryView";
- private static final boolean DEBUG = false;
+ private static final float TRANSLATION_Y_PCT = 0.25f;
+ private static final float BG_SCRIM_ALPHA = 0.625f;
private RecyclerView mRecyclerView;
private RecentsHistoryAdapter mAdapter;
private RecentsHistoryItemTouchCallbacks mItemTouchHandler;
+ private AnimateableViewBounds mViewBounds;
private boolean mIsVisible;
private Rect mSystemInsets = new Rect();
+ private int mHeaderHeight;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
private int mHistoryTransitionDuration;
public RecentsHistoryView(Context context) {
@@ -75,72 +81,95 @@
mAdapter = new RecentsHistoryAdapter(context);
mItemTouchHandler = new RecentsHistoryItemTouchCallbacks(context, mAdapter);
mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
+ mViewBounds = new AnimateableViewBounds(this, 0);
+ setOutlineProvider(mViewBounds);
}
/**
* Updates this history view with the recent tasks, and then shows it.
*/
- public void show(TaskStack stack, ReferenceCountedTrigger postHideAnimationTrigger) {
+ public void show(TaskStack stack, int stackHeight, View clearAllButton) {
setVisibility(View.VISIBLE);
setAlpha(0f);
- postHideAnimationTrigger.addLastDecrementRunnable(new Runnable() {
- @Override
- public void run() {
- animate()
- .alpha(1f)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
- .withLayer()
- .start();
- }
- });
+ setTranslationY(-stackHeight * TRANSLATION_Y_PCT);
+ animate()
+ .alpha(1f)
+ .translationY(0f)
+ .setDuration(mHistoryTransitionDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setUpdateListener(this)
+ .start();
+ clearAllButton.setVisibility(View.VISIBLE);
+ clearAllButton.setAlpha(0f);
+ clearAllButton.animate()
+ .alpha(1f)
+ .setDuration(mHistoryTransitionDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .withLayer()
+ .start();
mAdapter.updateTasks(getContext(), stack);
mIsVisible = true;
+ EventBus.getDefault().send(new UpdateBackgroundScrimEvent(BG_SCRIM_ALPHA));
- MetricsLogger.visible(mRecyclerView.getContext(), MetricsLogger.OVERVIEW_HISTORY);
+ MetricsLogger.visible(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
}
/**
* Hides this history view.
*/
- public void hide(boolean animate, final ReferenceCountedTrigger postAnimationTrigger) {
+ public void hide(boolean animate, int stackHeight, final View clearAllButton) {
if (animate) {
animate()
.alpha(0f)
+ .translationY(-stackHeight * TRANSLATION_Y_PCT)
.setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
+ .setUpdateListener(this)
.withEndAction(new Runnable() {
@Override
public void run() {
setVisibility(View.INVISIBLE);
- if (postAnimationTrigger != null) {
- postAnimationTrigger.decrement();
- }
+ }
+ })
+ .start();
+ clearAllButton.animate()
+ .alpha(0f)
+ .translationY(0f)
+ .setDuration(mHistoryTransitionDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ clearAllButton.setVisibility(View.INVISIBLE);
}
})
.withLayer()
.start();
- if (postAnimationTrigger != null) {
- postAnimationTrigger.increment();
- }
} else {
setAlpha(0f);
setVisibility(View.INVISIBLE);
+ clearAllButton.setAlpha(0f);
+ clearAllButton.setVisibility(View.INVISIBLE);
}
mIsVisible = false;
+ EventBus.getDefault().send(new ResetBackgroundScrimEvent());
- MetricsLogger.hidden(mRecyclerView.getContext(), MetricsLogger.OVERVIEW_HISTORY);
+ MetricsLogger.hidden(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
}
/**
* Updates the system insets of this history view to the provided values.
*/
public void setSystemInsets(Rect systemInsets) {
- mSystemInsets.set(systemInsets.left, systemInsets.top, systemInsets.right, systemInsets.bottom);
+ mSystemInsets.set(systemInsets);
+ requestLayout();
+ }
+
+ /**
+ * Updates the header height to account for the history button bar.
+ */
+ public void setHeaderHeight(int height) {
+ mHeaderHeight = height;
requestLayout();
}
@@ -175,7 +204,7 @@
int stackHeightPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.recents_stack_top_padding);
mRecyclerView.setPadding(stackWidthPadding + mSystemInsets.left,
- stackHeightPadding + mSystemInsets.top,
+ stackHeightPadding + mSystemInsets.top + mHeaderHeight,
stackWidthPadding + mSystemInsets.right, mSystemInsets.bottom);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -199,9 +228,25 @@
return insets;
}
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // Clip the top of the view by the header bar height
+ int top = Math.max(0, (int) -getTranslationY()) + mSystemInsets.top + mHeaderHeight;
+ mViewBounds.setClipTop(top);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
/**** EventBus Events ****/
public final void onBusEvent(PackagesChangedEvent event) {
mAdapter.removeTasks(event.packageName, event.userId);
}
+
+ public final void onBusEvent(ClearHistoryEvent event) {
+ mAdapter.removeAllTasks();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2882cec..d22cd53 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -65,6 +65,7 @@
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
import com.android.systemui.Prefs;
@@ -81,6 +82,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
/**
@@ -254,8 +256,6 @@
* Returns whether this device has freeform workspaces.
*/
public boolean hasFreeformWorkspaceSupport() {
- if (mPm == null) return false;
-
return mHasFreeformWorkspaceSupport;
}
@@ -266,8 +266,9 @@
ComponentName topActivity = topTask.topActivity;
// Check if the front most activity is recents
- if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
- topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
+ if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+ (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
+ topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
if (isHomeTopMost != null) {
isHomeTopMost.value = false;
}
@@ -356,6 +357,13 @@
}
/**
+ * Returns whether the given stack id is the pinned stack id.
+ */
+ public static boolean isPinnedStack(int stackId){
+ return stackId == PINNED_STACK_ID;
+ }
+
+ /**
* Returns whether the given stack id is the docked stack id.
*/
public static boolean isDockedStack(int stackId) {
@@ -968,4 +976,20 @@
public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
mWm.requestAppKeyboardShortcuts(receiver);
}
+
+ public void focusPinnedStack() {
+ try {
+ mIam.setFocusedStack(PINNED_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void focusHomeStack() {
+ try {
+ mIam.setFocusedStack(HOME_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index f3c4cc3..4deea54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -26,6 +26,7 @@
import android.util.Property;
import android.view.View;
import android.view.ViewParent;
+
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskViewTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index d9057b8..1f82c16 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.UserHandle;
+
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index d15828a..4e08bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -22,12 +22,12 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.os.Debug;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.SparseIntArray;
+
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -37,6 +37,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Formatter;
import java.util.List;
@@ -130,6 +131,7 @@
SparseIntArray affiliatedTaskCounts = new SparseIntArray();
String dismissDescFormat = mContext.getString(
R.string.accessibility_recents_item_will_be_dismissed);
+ Formatter dismissDescFormatter = new Formatter();
long lastStackActiveTime = Prefs.getLong(mContext,
Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
if (RecentsDebugFlags.Static.EnableMockTasks) {
@@ -168,7 +170,8 @@
// Load the title, icon, and color
String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
- String dismissDescription = String.format(dismissDescFormat, contentDescription);
+ String dismissDescription = dismissDescFormatter.format(dismissDescFormat,
+ contentDescription).toString();
Drawable icon = isStackTask
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 44ad239..26130ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -29,6 +29,7 @@
import android.os.HandlerThread;
import android.util.Log;
import android.util.LruCache;
+
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
@@ -334,10 +335,19 @@
}
}
- /** Acquires the task resource data directly from the pool. */
- public void loadTaskData(Task t) {
+ /**
+ * Acquires the task resource data directly from the cache, loading if necessary.
+ *
+ * @param fetchAndInvalidateThumbnails If set, will try loading thumbnails, invalidating them
+ * in the cache and loading if necessary. Otherwise, do not
+ * load the thumbnail unless the icon also has to be loaded.
+ */
+ public void loadTaskData(Task t, boolean fetchAndInvalidateThumbnails) {
Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
- Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+ Bitmap thumbnail = mDefaultThumbnail;
+ if (fetchAndInvalidateThumbnails) {
+ thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+ }
// Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
// use the default assets in their place until they load
@@ -360,6 +370,8 @@
mLoadQueue.removeTask(t);
mThumbnailCache.remove(t.key);
mIconCache.remove(t.key);
+ mActivityLabelCache.remove(t.key);
+ mContentDescriptionCache.remove(t.key);
mActivityInfoCache.remove(t.key.getComponent());
if (notifyTaskDataUnloaded) {
t.notifyTaskDataUnloaded(null, mDefaultIcon);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 193bd17..1c277d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -23,6 +23,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 66eeac6..aa8efa7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -33,6 +33,7 @@
import android.util.ArraySet;
import android.util.SparseArray;
import android.view.animation.Interpolator;
+
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -399,7 +400,12 @@
// Calculate the task stack bounds from the new window bounds
Rect searchBarSpaceBounds = new Rect();
Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(newWindowBounds, insets.top, insets.right,
+ // If the task stack bounds is specifically under the dock area, then ignore the top
+ // inset
+ int top = dockArea.bottom < 1f
+ ? 0
+ : insets.top;
+ config.getTaskStackBounds(newWindowBounds, top, insets.right,
searchBarSpaceBounds, taskStackBounds);
return taskStackBounds;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
new file mode 100644
index 0000000..fb86214
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.RecentsTvView;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.tv.pip.PipManager;
+
+import java.util.ArrayList;
+/**
+ * The main TV recents activity started by the RecentsImpl.
+ */
+public class RecentsTvActivity extends Activity implements OnPreDrawListener {
+ private final static String TAG = "RecentsTvActivity";
+ private final static boolean DEBUG = false;
+
+ public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+
+ private boolean mFinishedOnStartup;
+ private RecentsPackageMonitor mPackageMonitor;
+ private long mLastTabKeyEventTime;
+ private boolean mIgnoreAltTabRelease;
+
+ private RecentsTvView mRecentsView;
+ private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
+ private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+
+
+ /**
+ * A common Runnable to finish Recents by launching Home with an animation depending on the
+ * last activity launch state. Generally we always launch home when we exit Recents rather than
+ * just finishing the activity since we don't know what is behind Recents in the task stack.
+ */
+ class FinishRecentsRunnable implements Runnable {
+ Intent mLaunchIntent;
+
+ /**
+ * Creates a finish runnable that starts the specified intent.
+ */
+ public FinishRecentsRunnable(Intent launchIntent) {
+ mLaunchIntent = launchIntent;
+ }
+
+ @Override
+ public void run() {
+ try {
+ RecentsActivityLaunchState launchState =
+ Recents.getConfiguration().getLaunchState();
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_enter :
+ R.anim.recents_to_launcher_enter,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_exit :
+ R.anim.recents_to_launcher_exit);
+ startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+ } catch (Exception e) {
+ Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
+ }
+ }
+ }
+
+ private void updateRecentsTasks() {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+ if (plan == null) {
+ plan = loader.createLoadPlan(this);
+ }
+
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (!plan.hasTasks()) {
+ loader.preloadTasks(plan, -1, launchState.launchedFromHome);
+ }
+ TaskStack stack = plan.getTaskStack();
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.runningTaskId = launchState.launchedToTaskId;
+ loadOpts.numVisibleTasks = stack.getStackTaskCount();
+ loadOpts.numVisibleTaskThumbnails = stack.getStackTaskCount();
+ loader.loadTasks(this, plan, loadOpts);
+
+
+ mRecentsView.setTaskStack(stack);
+ if (mTaskStackViewAdapter == null) {
+ mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+ mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
+ } else {
+ mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+ }
+
+ if (launchState.launchedToTaskId != -1) {
+ ArrayList<Task> tasks = stack.getStackTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task t = tasks.get(i);
+ if (t.key.id == launchState.launchedToTaskId) {
+ t.isLaunchTarget = true;
+ break;
+ }
+ }
+ }
+ }
+
+ boolean dismissRecentsToLaunchTargetTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchPreviousTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+ return false;
+ }
+
+ boolean dismissRecentsToFocusedTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchFocusedTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ return true;
+ }
+ return false;
+ }
+
+ void dismissRecentsToHome(boolean animateTaskViews) {
+ DismissRecentsToHomeAnimationStarted dismissEvent =
+ new DismissRecentsToHomeAnimationStarted(animateTaskViews);
+ dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+ dismissEvent.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ }
+ });
+ EventBus.getDefault().send(dismissEvent);
+ }
+
+ boolean dismissRecentsToHomeIfVisible(boolean animated) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // Return to Home
+ dismissRecentsToHome(animated);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mFinishedOnStartup = false;
+
+ // In the case that the activity starts up before the Recents component has initialized
+ // (usually when debugging/pushing the SysUI apk), just finish this activity.
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp == null) {
+ mFinishedOnStartup = true;
+ finish();
+ return;
+ }
+
+ // Register this activity with the event bus
+ EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
+ mPackageMonitor = new RecentsPackageMonitor();
+ mPackageMonitor.register(this);
+
+ // Set the Recents layout
+ setContentView(R.layout.recents_on_tv);
+
+ mRecentsView = (RecentsTvView) findViewById(R.id.recents_view);
+ mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
+ // Create the home intent runnable
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // Update the recent tasks
+ updateRecentsTasks();
+
+ // If this is a new instance from a configuration change, then we have to manually trigger
+ // the enter animation state, or if recents was relaunched by AM, without going through
+ // the normal mechanisms
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+ !launchState.launchedFromAppWithThumbnail;
+ if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ // Notify that recents is now visible
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+ }
+
+ @Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ mIgnoreAltTabRelease = false;
+ // Notify that recents is now hidden
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+
+ // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+ // through SystemUI, we need to reset the config launch flags to ensure that we do not
+ // wait on the system to send a signal that was never queued.
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ launchState.launchedFromHome = false;
+ launchState.launchedFromSearchHome = false;
+ launchState.launchedFromAppWithThumbnail = false;
+ launchState.launchedToTaskId = -1;
+ launchState.launchedWithAltTab = false;
+ launchState.launchedHasConfigurationChanged = false;
+ launchState.launchedViaDragGesture = false;
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // In the case that the activity finished on startup, just skip the unregistration below
+ if (mFinishedOnStartup) {
+ return;
+ }
+
+ // Unregister any broadcast receivers for the task loader
+ mPackageMonitor.unregister();
+
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ if (loader != null) {
+ loader.onTrimMemory(level);
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipMenu();
+ ssp.focusPinnedStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DPAD_DOWN: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipOverlay(false);
+ ssp.focusHomeStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DEL:
+ case KeyEvent.KEYCODE_FORWARD_DEL: {
+ EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+ return true;
+ }
+ default:
+ break;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public void onUserInteraction() {
+ EventBus.getDefault().send(new UserInteractionEvent());
+ }
+
+ @Override
+ public void onBackPressed() {
+ // Back behaves like the recents button so just trigger a toggle event
+ EventBus.getDefault().send(new ToggleRecentsEvent());
+ }
+
+ /**** EventBus events ****/
+
+ public final void onBusEvent(ToggleRecentsEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ if (launchState.launchedFromHome) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+ }
+
+ public final void onBusEvent(HideRecentsEvent event) {
+ if (event.triggeredFromAltTab) {
+ // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+ if (!mIgnoreAltTabRelease) {
+ dismissRecentsToFocusedTaskOrHome();
+ }
+ } else if (event.triggeredFromHomeKey) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ // Do nothing
+ }
+ }
+
+ public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+ EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ mRecentsView.invalidate();
+ }
+
+ public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ int launchToTaskId = launchState.launchedToTaskId;
+ if (launchToTaskId != -1 &&
+ (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.cancelWindowTransition(launchState.launchedToTaskId);
+ ssp.cancelThumbnailTransition(getTaskId());
+ }
+ }
+
+ public final void onBusEvent(DeleteTaskDataEvent event) {
+ // Remove any stored data from the loader
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ loader.deleteTaskData(event.task, false);
+
+ // Remove the task from activity manager
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.removeTask(event.task.key.id);
+ }
+
+ public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.hasDockedTask()) {
+ mRecentsView.showEmptyView();
+ } else {
+ // Just go straight home (no animation necessary because there are no more task views)
+ dismissRecentsToHome(false /* animateTaskViews */);
+ }
+ }
+
+ public final void onBusEvent(LaunchTaskFailedEvent event) {
+ // Return to Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ // We post to make sure that this information is delivered after this traversals is
+ // finished.
+ mRecentsView.post(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().endProlongedAnimations();
+ }
+ });
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
new file mode 100644
index 0000000..8028327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
+
+public class ViewFocusAnimator implements View.OnFocusChangeListener {
+ private final float mUnselectedScale;
+ private final float mSelectedScaleDelta;
+ private final float mUnselectedZ;
+ private final float mSelectedZDelta;
+ private final int mAnimDuration;
+ private final Interpolator mFocusInterpolator;
+
+ protected View mTargetView;
+ private float mFocusProgress;
+
+ ObjectAnimator mFocusAnimation;
+
+ public ViewFocusAnimator(View view) {
+ mTargetView = view;
+ final Resources res = view.getResources();
+
+ mTargetView.setOnFocusChangeListener(this);
+
+ TypedValue out = new TypedValue();
+ res.getValue(R.raw.unselected_scale, out, true);
+ mUnselectedScale = out.getFloat();
+ mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
+ mUnselectedScale;
+
+ mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
+ mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
+
+ mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
+
+ mFocusInterpolator = new AccelerateDecelerateInterpolator();
+
+ mFocusAnimation = ObjectAnimator.ofFloat(this, "focusProgress", 0.0f);
+ mFocusAnimation.setDuration(mAnimDuration);
+ mFocusAnimation.setInterpolator(mFocusInterpolator);
+
+ setFocusProgress(0.0f);
+
+ mFocusAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTargetView.setHasTransientState(true);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTargetView.setHasTransientState(false);
+ }
+ });
+ }
+
+ public void setFocusProgress(float level) {
+ mFocusProgress = level;
+
+ float scale = mUnselectedScale + (level * mSelectedScaleDelta);
+ float z = mUnselectedZ + (level * mSelectedZDelta);
+
+ mTargetView.setScaleX(scale);
+ mTargetView.setScaleY(scale);
+ mTargetView.setZ(z);
+ }
+
+ public float getFocusProgress() {
+ return mFocusProgress;
+ }
+
+ public void animateFocus(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ if (getFocusProgress() != target) {
+ mFocusAnimation.setFloatValues(getFocusProgress(), target);
+ mFocusAnimation.start();
+ }
+ }
+
+ public void setFocusImmediate(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ setFocusProgress(target);
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v != mTargetView) {
+ return;
+ }
+ changeSize(hasFocus);
+ }
+
+ protected void changeSize(boolean hasFocus) {
+ ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
+ int width = lp.width;
+ int height = lp.height;
+
+ if (width < 0 && height < 0) {
+ mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mTargetView.getMeasuredHeight();
+ }
+
+ if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
+ mTargetView.getVisibility() == View.VISIBLE) {
+ animateFocus(hasFocus);
+ } else {
+ setFocusImmediate(hasFocus);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
new file mode 100644
index 0000000..b175855
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
+ */
+public class RecentsTvView extends FrameLayout {
+
+ private static final String TAG = "RecentsTvView";
+ private static final boolean DEBUG = false;
+
+ private TaskStack mStack;
+ private TaskStackHorizontalGridView mTaskStackHorizontalView;
+ private View mEmptyView;
+ private boolean mAwaitingFirstLayout = true;
+ private Rect mSystemInsets = new Rect();
+
+
+ public RecentsTvView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ setWillNotDraw(false);
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+ addView(mEmptyView);
+ }
+
+ public void setTaskStack(TaskStack stack) {
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ mStack = stack;
+
+ if (mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.reset();
+ mTaskStackHorizontalView.setStack(stack);
+ } else {
+ mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
+ mTaskStackHorizontalView.setStack(stack);
+ }
+
+
+ if (stack.getStackTaskCount() > 0) {
+ hideEmptyView();
+ } else {
+ showEmptyView();
+ }
+
+ requestLayout();
+ }
+
+ public Task getNextTaskOrTopTask(Task taskToSearch) {
+ Task returnTask = null;
+ boolean found = false;
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ ArrayList<Task> taskList = stack.getStackTasks();
+ // Iterate the stack views and try and find the focused task
+ for (int j = taskList.size() - 1; j >= 0; --j) {
+ Task task = taskList.get(j);
+ // Return the next task in the line.
+ if (found)
+ return task;
+ // Remember the first possible task as the top task.
+ if (returnTask == null)
+ returnTask = task;
+ if (task == taskToSearch)
+ found = true;
+ }
+ }
+ return returnTask;
+ }
+
+ public boolean launchFocusedTask() {
+ if (mTaskStackHorizontalView != null) {
+ Task task = mTaskStackHorizontalView.getFocusedTask();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches the task that recents was launched from if possible */
+ public boolean launchPreviousTask() {
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ Task task = stack.getLaunchTarget();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches a given task. */
+ public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
+ if (mTaskStackHorizontalView != null) {
+ // Iterate the stack views and try and find the given task.
+ List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int j = 0; j < taskViewCount; j++) {
+ TaskCardView tv = taskViews.get(j);
+ if (tv.getTask() == task) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Hides the task stack and shows the empty view.
+ */
+ public void showEmptyView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.bringToFront();
+ }
+
+ /**
+ * Shows the task stack and hides the empty view.
+ */
+ public void hideEmptyView() {
+ mEmptyView.setVisibility(View.INVISIBLE);
+ }
+
+ /**
+ * Returns the last known system insets.
+ */
+ public Rect getSystemInsets() {
+ return mSystemInsets;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
+ /**
+ * This is called with the full size of the window since we are handling our own insets.
+ */
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
+ mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
+ }
+
+ // Layout the empty view
+ mEmptyView.layout(left, top, right, bottom);
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mSystemInsets.set(insets.getSystemWindowInsets());
+ requestLayout();
+ return insets;
+ }
+
+ /**** EventBus Events ****/
+
+ public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+ // If we are going home, cancel the previous task's window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+ }
+
+ public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+ if (!event.visible) {
+ // Reset the view state
+ mAwaitingFirstLayout = true;
+ }
+ }
+
+ public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) {
+ if(mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
new file mode 100644
index 0000000..e275f22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+
+public class TaskCardView extends RelativeLayout {
+
+ private ImageView mThumbnailView;
+ private TextView mTitleTextView;
+ private TextView mContentTextView;
+ private ImageView mBadgeView;
+ private Task mTask;
+
+ private ViewFocusAnimator mViewFocusAnimator;
+
+ public TaskCardView(Context context) {
+ this(context, null);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mViewFocusAnimator = new ViewFocusAnimator(this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+ mTitleTextView = (TextView) findViewById(R.id.card_title_text);
+ mContentTextView = (TextView) findViewById(R.id.card_content_text);
+ mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+ }
+
+ public void init(Task task) {
+ mTask = task;
+ mThumbnailView.setImageBitmap(task.thumbnail);
+ mTitleTextView.setText(task.title);
+ mContentTextView.setText(task.contentDescription);
+ mBadgeView.setImageDrawable(task.icon);
+ }
+
+ public Task getTask() {
+ return mTask;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
new file mode 100644
index 0000000..2d41742
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+
+import android.content.Context;
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
+import com.android.systemui.recents.views.TaskViewAnimation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Horizontal Grid View Implementation to show the Task Stack for TV.
+ */
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+
+ private TaskStack mStack;
+ private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
+ private Task mFocusedTask;
+
+
+ public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+ /**
+ * Resets this view for reuse.
+ */
+ public void reset() {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+ requestLayout();
+ }
+
+ /**
+ * @param task - Task to reset
+ */
+ private void resetFocusedTask(Task task) {
+ if (task != null) {
+ TaskCardView tv = getChildViewForTask(task);
+ if (tv != null) {
+ tv.requestFocus();
+ }
+ }
+ mFocusedTask = null;
+ }
+
+ /**
+ * Sets the task stack.
+ * @param stack
+ */
+ public void setStack(TaskStack stack) {
+ //Set new stack
+ mStack = stack;
+ if (mStack != null) {
+ mStack.setCallbacks(this);
+ }
+ //Layout with new stack
+ requestLayout();
+ }
+
+ /**
+ * @return Returns the task stack.
+ */
+ public TaskStack getStack() {
+ return mStack;
+ }
+
+ /**
+ * @return - The focused task.
+ */
+ public Task getFocusedTask() {
+ return mFocusedTask;
+ }
+
+ /**
+ * @param task
+ * @return Child view for given task
+ */
+ public TaskCardView getChildViewForTask(Task task) {
+ List<TaskCardView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskCardView tv = taskViews.get(i);
+ if (tv.getTask() == task) {
+ return tv;
+ }
+ }
+ return null;
+ }
+
+ public List<TaskCardView> getTaskViews() {
+ return mTaskViews;
+ }
+
+ @Override
+ public void onStackTaskAdded(TaskStack stack, Task newTask){
+ getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
+ }
+
+ @Override
+ public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
+ Task newFrontMostTask, TaskViewAnimation animation) {
+ getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+ if (mFocusedTask == removedTask) {
+ resetFocusedTask(removedTask);
+ }
+ // If there are no remaining tasks, then just close recents
+ if (mStack.getStackTaskCount() == 0) {
+ boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
+ if (shouldFinishActivity) {
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+ }
+ }
+ }
+
+ @Override
+ public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation) {
+ //No history task on tv
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
new file mode 100644
index 0000000..7b62f4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskStackHorizontalViewAdapter extends
+ RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
+
+ private static final String TAG = "TaskStackHorizontalViewAdapter";
+ private List<Task> mTaskList;
+
+ static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+ private TaskCardView mTaskCardView;
+ private Task mTask;
+ public ViewHolder(View v) {
+ super(v);
+ if(v instanceof TaskCardView) {
+ mTaskCardView = (TaskCardView) v;
+ }
+ }
+
+ public void init(Task task) {
+ mTaskCardView.init(task);
+ mTask = task;
+ mTaskCardView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ try {
+ ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+ ((Activity)(v.getContext())).finish();
+ } catch (Exception e) {
+ Log.e(TAG, v.getContext()
+ .getString(R.string.recents_launch_error_message, mTask.title), e);
+ }
+
+ }
+ }
+
+ public TaskStackHorizontalViewAdapter(List tasks) {
+ mTaskList = new ArrayList<>(tasks);
+ }
+
+ public void setNewStackTasks(List tasks) {
+ mTaskList.clear();
+ mTaskList.addAll(tasks);
+ notifyDataSetChanged();
+ }
+ @Override
+ public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.recents_task_card_view, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.init(mTaskList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mTaskList.size();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 5a72897..5842095 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -48,10 +48,16 @@
@Override
public void getOutline(View view, Outline outline) {
outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
- outline.setRoundRect(mClipRect.left, mClipRect.top,
- mSourceView.getWidth() - mClipRect.right,
- mSourceView.getHeight() - mClipRect.bottom,
- mCornerRadius);
+ if (mCornerRadius > 0) {
+ outline.setRoundRect(mClipRect.left, mClipRect.top,
+ mSourceView.getWidth() - mClipRect.right,
+ mSourceView.getHeight() - mClipRect.bottom,
+ mCornerRadius);
+ } else {
+ outline.setRect(mClipRect.left, mClipRect.top,
+ mSourceView.getWidth() - mClipRect.right,
+ mSourceView.getHeight() - mClipRect.bottom);
+ }
}
/** Sets the view outline alpha. */
@@ -63,6 +69,17 @@
}
}
+ /** Sets the top clip. */
+ public void setClipTop(int top) {
+ mClipRect.top = top;
+ updateClipBounds();
+ }
+
+ /** Returns the top clip. */
+ public int getClipTop() {
+ return mClipRect.top;
+ }
+
/** Sets the bottom clip. */
public void setClipBottom(int bottom) {
mClipRect.bottom = bottom;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 682fd8f..d64a676 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,6 +28,7 @@
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.Log;
+
import com.android.systemui.R;
import com.android.systemui.recents.RecentsConfiguration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
index f5ab01f..d3b5e47 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
@@ -20,13 +20,14 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.widget.ImageView;
+
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
/**
* This is an optimized ImageView that does not trigger a <code>requestLayout()</code> or
* <code>invalidate()</code> when setting the image to <code>null</code>.
*/
-public class FixedSizeImageView extends ImageView {
+public class FixedSizeImageView extends AlphaOptimizedImageView {
private boolean mAllowRelayout = true;
private boolean mAllowInvalidate = true;
@@ -73,9 +74,4 @@
mAllowRelayout = true;
mAllowInvalidate = true;
}
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 491c4c2..511aa3c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.graphics.RectF;
import android.util.ArrayMap;
+
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index b363ed5..3fdd771 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -31,6 +31,7 @@
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.WindowManagerGlobal;
+
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index e448101..e2ff52c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -18,9 +18,13 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Outline;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.ArraySet;
@@ -28,13 +32,15 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -43,20 +49,25 @@
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ClearHistoryEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
+import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
+import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.history.RecentsHistoryView;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
@@ -64,7 +75,6 @@
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
import java.util.List;
@@ -78,6 +88,8 @@
public class RecentsView extends FrameLayout {
private static final int DOCK_AREA_OVERLAY_TRANSITION_DURATION = 135;
+ private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
+ private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
private final Handler mHandler;
@@ -85,17 +97,20 @@
private TaskStackView mTaskStackView;
private RecentsAppWidgetHostView mSearchBar;
private TextView mHistoryButton;
+ private TextView mHistoryClearAllButton;
private View mEmptyView;
+ private RecentsHistoryView mHistoryView;
+
private boolean mAwaitingFirstLayout = true;
private boolean mLastTaskLaunchedWasFreeform;
private Rect mSystemInsets = new Rect();
private int mDividerSize;
+ private ColorDrawable mBackgroundScrim = new ColorDrawable(Color.BLACK);
+ private Animator mBackgroundScrimAnimator;
+
private RecentsTransitionHelper mTransitionHelper;
private RecentsViewTouchHandler mTouchHandler;
-
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mFastOutLinearInInterpolator;
private final FlingAnimationUtils mFlingAnimationUtils;
public RecentsView(Context context) {
@@ -117,25 +132,32 @@
SystemServicesProxy ssp = Recents.getSystemServices();
mHandler = new Handler();
mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
mDividerSize = ssp.getDockedDividerSize(context);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
+ final float cornerRadius = context.getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
LayoutInflater inflater = LayoutInflater.from(context);
mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
mHistoryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- EventBus.getDefault().send(new ShowHistoryEvent());
+ EventBus.getDefault().send(new ToggleHistoryEvent());
}
});
addView(mHistoryButton);
+ mHistoryButton.setClipToOutline(true);
+ mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+ }
+ });
mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
addView(mEmptyView);
+
+ setBackground(mBackgroundScrim);
}
/** Set/get the bsp root node */
@@ -160,6 +182,15 @@
addView(mTaskStackView);
}
+ // If we are already occluded by the app, then just set the default background scrim now.
+ // Otherwise, defer until the enter animation completes to animate the scrim with the
+ // tasks for the home animation.
+ if (launchState.launchedFromAppWithThumbnail || mStack.getTaskCount() == 0) {
+ mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+ } else {
+ mBackgroundScrim.setAlpha(0);
+ }
+
// Update the top level view's visibilities
if (stack.getTaskCount() > 0) {
hideEmptyView();
@@ -179,6 +210,13 @@
}
/**
+ * Returns whether the history is visible or not.
+ */
+ public boolean isHistoryVisible() {
+ return mHistoryView != null && mHistoryView.isVisible();
+ }
+
+ /**
* Returns the currently set task stack.
*/
public TaskStack getTaskStack() {
@@ -302,13 +340,6 @@
mHistoryButton.bringToFront();
}
- /**
- * Returns the last known system insets.
- */
- public Rect getSystemInsets() {
- return mSystemInsets;
- }
-
@Override
protected void onAttachedToWindow() {
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -350,17 +381,28 @@
mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
}
- // Measure the empty view
- measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ // Measure the empty view to the full size of the screen
+ if (mEmptyView.getVisibility() != GONE) {
+ measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
- // Measure the history button with the full space above the stack, but width-constrained
- // to the stack
+ // Measure the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+
+ // Measure the history button within the constraints of the space above the stack
Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
measureChild(mHistoryButton,
- MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(historyButtonRect.height(),
- MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ measureChild(mHistoryClearAllButton,
+ MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ }
setMeasuredDimension(width, height);
}
@@ -387,13 +429,41 @@
}
// Layout the empty view
- mEmptyView.layout(left, top, right, bottom);
+ if (mEmptyView.getVisibility() != GONE) {
+ mEmptyView.layout(left, top, right, bottom);
+ }
- // Layout the history button left-aligned with the stack, but offset from the top of the
- // view
+ // Layout the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ mHistoryView.layout(left, top, right, bottom);
+ }
+
+ // Layout the history button such that its drawable is start-aligned with the stack,
+ // vertically centered in the available space above the stack
Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- mHistoryButton.layout(historyButtonRect.left, historyButtonRect.top,
- historyButtonRect.right, historyButtonRect.bottom);
+ int historyLeft = isLayoutRtl()
+ ? historyButtonRect.right + mHistoryButton.getPaddingStart()
+ - mHistoryButton.getMeasuredWidth()
+ : historyButtonRect.left - mHistoryButton.getPaddingStart();
+ int historyTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
+ mHistoryButton.layout(historyLeft, historyTop,
+ historyLeft + mHistoryButton.getMeasuredWidth(),
+ historyTop + mHistoryButton.getMeasuredHeight());
+
+ // Layout the history clear all button such that it is end-aligned with the stack,
+ // vertically centered in the available space above the stack
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ int clearAllLeft = isLayoutRtl()
+ ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
+ : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
+ - mHistoryClearAllButton.getMeasuredWidth();
+ int clearAllTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) / 2;
+ mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
+ clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
+ clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+ }
if (mAwaitingFirstLayout) {
mAwaitingFirstLayout = false;
@@ -462,10 +532,8 @@
// Hide the history button
int taskViewExitToHomeDuration = getResources().getInteger(
R.integer.recents_task_exit_to_home_duration);
- hideHistoryButton(taskViewExitToHomeDuration);
-
- // If we are going home, cancel the previous task's window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+ hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ animateBackgroundScrim(0f, taskViewExitToHomeDuration);
}
public final void onBusEvent(DragStartEvent event) {
@@ -520,7 +588,7 @@
tmpTransform.scale = 1f;
tmpTransform.rect.set(taskViewRect);
mTaskStackView.updateTaskViewToTransform(event.taskView, tmpTransform,
- new TaskViewAnimation(125, PhoneStatusBar.ALPHA_OUT,
+ new TaskViewAnimation(125, Interpolators.ALPHA_OUT,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -532,13 +600,12 @@
// Animate the stack accordingly
TaskViewAnimation stackAnim = new TaskViewAnimation(
TaskStackView.DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
mTaskStackView.getStack().removeTask(event.task, stackAnim);
}
}));
- MetricsLogger.action(mContext,
- MetricsLogger.ACTION_WINDOW_DOCK_DRAG_DROP);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP);
} else {
// Animate the overlay alpha back to 0
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
@@ -571,94 +638,195 @@
animator.start();
}
- public final void onBusEvent(ShowHistoryEvent event) {
- // Hide the history button when the history view is shown
- hideHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
- event.getAnimationTrigger());
- event.addPostAnimationCallback(new Runnable() {
- @Override
- public void run() {
- setAlpha(0f);
- }
- });
- }
-
- public final void onBusEvent(HideHistoryEvent event) {
- // Show the history button when the history view is hidden
- setAlpha(1f);
- showHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
- event.getAnimationTrigger());
- }
-
- public final void onBusEvent(ShowHistoryButtonEvent event) {
- showHistoryButton(150);
- }
-
- public final void onBusEvent(HideHistoryButtonEvent event) {
- hideHistoryButton(100);
- }
-
public final void onBusEvent(TaskStackUpdatedEvent event) {
mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
mStack.createAffiliatedGroupings(getContext());
}
+ public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ if (!launchState.launchedFromAppWithThumbnail && mStack.getTaskCount() > 0) {
+ int taskViewEnterFromHomeDuration = getResources().getInteger(
+ R.integer.recents_task_enter_from_home_duration);
+ animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, taskViewEnterFromHomeDuration);
+ }
+ }
+
+ public final void onBusEvent(UpdateBackgroundScrimEvent event) {
+ animateBackgroundScrim(event.alpha, DEFAULT_UPDATE_SCRIM_DURATION);
+ }
+
+ public final void onBusEvent(ResetBackgroundScrimEvent event) {
+ animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
+ }
+
+ public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+ if (!event.visible) {
+ // Reset the view state
+ mAwaitingFirstLayout = true;
+ mLastTaskLaunchedWasFreeform = false;
+ hideHistoryButton(0, false /* translate */);
+ }
+ }
+
+ public final void onBusEvent(ToggleHistoryEvent event) {
+ if (mHistoryView != null && mHistoryView.isVisible()) {
+ EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
+ } else {
+ EventBus.getDefault().send(new ShowHistoryEvent());
+ }
+ }
+
+ public final void onBusEvent(ShowHistoryEvent event) {
+ if (mHistoryView == null) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
+ false);
+ addView(mHistoryView);
+
+ final float cornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
+ mHistoryClearAllButton = (TextView) inflater.inflate(
+ R.layout.recents_history_clear_all_button, this, false);
+ mHistoryClearAllButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EventBus.getDefault().send(new ClearHistoryEvent());
+ }
+ });
+ mHistoryClearAllButton.setClipToOutline(true);
+ mHistoryClearAllButton.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+ }
+ });
+ addView(mHistoryClearAllButton);
+
+ // Since this history view is inflated by a view stub after the insets have already
+ // been applied, we have to set them ourselves initial from the insets that were last
+ // provided.
+ mHistoryView.setSystemInsets(mSystemInsets);
+ mHistoryView.setHeaderHeight(mHistoryButton.getMeasuredHeight());
+ mHistoryButton.bringToFront();
+ mHistoryClearAllButton.bringToFront();
+ }
+
+ // Animate the empty view in parallel with the history view (the task view animations are
+ // handled in TaskStackView)
+ Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
+ if (mEmptyView.getVisibility() == View.VISIBLE) {
+ int historyTransitionDuration = getResources().getInteger(
+ R.integer.recents_history_transition_duration);
+ mEmptyView.animate()
+ .alpha(0f)
+ .translationY(stackRect.height() / 2)
+ .setDuration(historyTransitionDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mEmptyView.setVisibility(View.INVISIBLE);
+ }
+ })
+ .start();
+ }
+
+ mHistoryView.show(mStack, stackRect.height(), mHistoryClearAllButton);
+ }
+
+ public final void onBusEvent(HideHistoryEvent event) {
+ // Animate the empty view in parallel with the history view (the task view animations are
+ // handled in TaskStackView)
+ Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
+ if (mStack.getTaskCount() == 0) {
+ int historyTransitionDuration = getResources().getInteger(
+ R.integer.recents_history_transition_duration);
+ mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.animate()
+ .alpha(1f)
+ .translationY(0)
+ .setDuration(historyTransitionDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .start();
+ }
+
+ mHistoryView.hide(event.animate, stackRect.height(), mHistoryClearAllButton);
+ }
+
+ public final void onBusEvent(ShowHistoryButtonEvent event) {
+ showHistoryButton(150, event.translate);
+ }
+
+ public final void onBusEvent(HideHistoryButtonEvent event) {
+ hideHistoryButton(100, true /* translate */);
+ }
+
/**
* Shows the history button.
*/
- private void showHistoryButton(final int duration) {
- ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
- showHistoryButton(duration, postAnimationTrigger);
- postAnimationTrigger.flushLastDecrementRunnables();
- }
-
- private void showHistoryButton(final int duration,
- final ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
- mHistoryButton.setText(getContext().getString(R.string.recents_history_label_format,
- mStack.getHistoricalTasks().size()));
+ private void showHistoryButton(final int duration, final boolean translate) {
+ final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
if (mHistoryButton.getVisibility() == View.INVISIBLE) {
mHistoryButton.setVisibility(View.VISIBLE);
mHistoryButton.setAlpha(0f);
- postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ if (translate) {
+ mHistoryButton.setTranslationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+ } else {
+ mHistoryButton.setTranslationY(0f);
+ }
+ postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
@Override
public void run() {
+ if (translate) {
+ mHistoryButton.animate()
+ .translationY(0f);
+ }
mHistoryButton.animate()
.alpha(1f)
.setDuration(duration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withLayer()
.start();
}
});
}
+ postAnimationTrigger.flushLastDecrementRunnables();
}
/**
* Hides the history button.
*/
- private void hideHistoryButton(int duration) {
- ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
- hideHistoryButton(duration, postAnimationTrigger);
+ private void hideHistoryButton(int duration, boolean translate) {
+ final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
+ hideHistoryButton(duration, translate, postAnimationTrigger);
postAnimationTrigger.flushLastDecrementRunnables();
}
- private void hideHistoryButton(int duration,
- final ReferenceCountedTrigger postHideStackAnimationTrigger) {
+ /**
+ * Hides the history button.
+ */
+ private void hideHistoryButton(int duration, boolean translate,
+ final ReferenceCountedTrigger postAnimationTrigger) {
if (mHistoryButton.getVisibility() == View.VISIBLE) {
+ if (translate) {
+ mHistoryButton.animate()
+ .translationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+ }
mHistoryButton.animate()
.alpha(0f)
.setDuration(duration)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
mHistoryButton.setVisibility(View.INVISIBLE);
- postHideStackAnimationTrigger.decrement();
+ postAnimationTrigger.decrement();
}
})
.withLayer()
.start();
- postHideStackAnimationTrigger.increment();
+ postAnimationTrigger.increment();
}
}
@@ -677,7 +845,7 @@
if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
// This is no longer visible, so hide it
viewState.startAnimation(null, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
- PhoneStatusBar.ALPHA_OUT, animateAlpha, animateBounds);
+ Interpolators.ALPHA_OUT, animateAlpha, animateBounds);
} else {
// This state is now visible, update the bounds and show it
int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
@@ -690,16 +858,23 @@
viewState.dockAreaOverlay.setBounds(bounds);
}
viewState.startAnimation(bounds, alpha, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
- PhoneStatusBar.ALPHA_IN, animateAlpha, animateBounds);
+ Interpolators.ALPHA_IN, animateAlpha, animateBounds);
}
}
}
- public final void onBusEvent(RecentsVisibilityChangedEvent event) {
- if (!event.visible) {
- // Reset the view state
- mAwaitingFirstLayout = true;
- mLastTaskLaunchedWasFreeform = false;
- }
+ /**
+ * Animates the background scrim to the given {@param alpha}.
+ */
+ private void animateBackgroundScrim(float alpha, int duration) {
+ Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
+ int alphaInt = (int) (alpha * 255);
+ mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
+ mBackgroundScrim.getAlpha(), alphaInt);
+ mBackgroundScrimAnimator.setDuration(duration);
+ mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
+ ? Interpolators.ALPHA_OUT
+ : Interpolators.ALPHA_IN);
+ mBackgroundScrimAnimator.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index d8698ee..346ce16 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
@@ -149,7 +150,8 @@
}
// Request other drop targets to register themselves
- EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task, this));
+ EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task,
+ event.taskView, this));
}
public final void onBusEvent(DragEndEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 9618f212d..e8fa398 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -19,8 +19,8 @@
import android.app.Activity;
import android.content.Context;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -30,46 +30,30 @@
Context mContext;
- View mStatusBarScrimView;
View mNavBarScrimView;
boolean mHasNavBarScrim;
- boolean mShouldAnimateStatusBarScrim;
- boolean mHasStatusBarScrim;
boolean mShouldAnimateNavBarScrim;
int mNavBarScrimEnterDuration;
- Interpolator mFastOutSlowInInterpolator;
- Interpolator mQuintOutInterpolator;
-
public SystemBarScrimViews(Activity activity) {
mContext = activity;
- mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
mNavBarScrimEnterDuration = activity.getResources().getInteger(
R.integer.recents_nav_bar_scrim_enter_duration);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity,
- com.android.internal.R.interpolator.decelerate_quint);
}
/**
* Prepares the scrim views for animating when entering Recents. This will be called before
* the first draw.
*/
- public void prepareEnterRecentsAnimation(boolean hasStatusBarScrim, boolean animateStatusBarScrim,
- boolean hasNavBarScrim, boolean animateNavBarScrim) {
- mHasNavBarScrim = hasStatusBarScrim;
- mShouldAnimateStatusBarScrim = animateStatusBarScrim;
- mHasStatusBarScrim = hasNavBarScrim;
+ public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+ mHasNavBarScrim = hasNavBarScrim;
mShouldAnimateNavBarScrim = animateNavBarScrim;
mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
View.VISIBLE : View.INVISIBLE);
- mStatusBarScrimView.setVisibility(mHasStatusBarScrim && !mShouldAnimateStatusBarScrim ?
- View.VISIBLE : View.INVISIBLE);
}
/**** EventBus events ****/
@@ -78,26 +62,12 @@
* Starts animating the scrim views when entering Recents.
*/
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
- if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
- mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
- mStatusBarScrimView.animate()
- .translationY(0)
- .setDuration(mNavBarScrimEnterDuration)
- .setInterpolator(mQuintOutInterpolator)
- .withStartAction(new Runnable() {
- @Override
- public void run() {
- mStatusBarScrimView.setVisibility(View.VISIBLE);
- }
- })
- .start();
- }
if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
mNavBarScrimView.animate()
.translationY(0)
.setDuration(mNavBarScrimEnterDuration)
- .setInterpolator(mQuintOutInterpolator)
+ .setInterpolator(Interpolators.DECELERATE_QUINT)
.withStartAction(new Runnable() {
@Override
public void run() {
@@ -115,20 +85,12 @@
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
int taskViewExitToAppDuration = mContext.getResources().getInteger(
R.integer.recents_task_exit_to_app_duration);
- if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
- mStatusBarScrimView.animate()
- .translationY(-mStatusBarScrimView.getMeasuredHeight())
- .setStartDelay(0)
- .setDuration(taskViewExitToAppDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
- .start();
- }
if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
mNavBarScrimView.animate()
.translationY(mNavBarScrimView.getMeasuredHeight())
.setStartDelay(0)
.setDuration(taskViewExitToAppDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index ccbb329..682c298 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -22,8 +22,8 @@
import android.content.res.Resources;
import android.graphics.RectF;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -31,7 +31,6 @@
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.List;
@@ -66,20 +65,10 @@
private TaskStackView mStackView;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
- private Interpolator mQuintOutInterpolator;
-
private TaskViewTransform mTmpTransform = new TaskViewTransform();
public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
mStackView = stackView;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.decelerate_quint);
}
/**
@@ -138,7 +127,7 @@
} else if (launchState.launchedFromHome) {
// Move the task view off screen (below) so we can animate it in
RectF bounds = new RectF(mTmpTransform.rect);
- bounds.offset(0, offscreenY);
+ bounds.offsetTo(bounds.left, offscreenY);
tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
(int) bounds.bottom);
}
@@ -198,7 +187,7 @@
// Animate the task up if it was occluding the launch target
if (currentTaskOccludesLaunchTarget) {
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- taskViewEnterFromAffiliatedAppDuration, PhoneStatusBar.ALPHA_IN,
+ taskViewEnterFromAffiliatedAppDuration, Interpolators.ALPHA_IN,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -219,7 +208,7 @@
frontIndex * taskViewEnterFromHomeStaggerDelay;
TaskViewAnimation taskAnimation = new TaskViewAnimation(delay,
- duration, mQuintOutInterpolator,
+ duration, Interpolators.DECELERATE_QUINT,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -253,13 +242,13 @@
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- animated ? taskViewExitToHomeDuration : 0, mFastOutLinearInInterpolator,
+ animated ? taskViewExitToHomeDuration : 0, Interpolators.FAST_OUT_LINEAR_IN,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
- mTmpTransform.rect.offset(0, offscreenY);
+ mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
}
@@ -295,7 +284,7 @@
} else if (currentTaskOccludesLaunchTarget) {
// Animate this task out of view
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- taskViewExitToAppDuration, PhoneStatusBar.ALPHA_OUT,
+ taskViewExitToAppDuration, Interpolators.ALPHA_OUT,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
@@ -327,7 +316,7 @@
// Compose the new animation and transform and star the animation
TaskViewAnimation taskAnimation = new TaskViewAnimation(taskViewRemoveAnimDuration,
- PhoneStatusBar.ALPHA_OUT, new AnimatorListenerAdapter() {
+ Interpolators.ALPHA_OUT, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
postAnimationTrigger.decrement();
@@ -346,61 +335,58 @@
}
/**
- * Starts the animation to hide the {@link TaskView}s when the history is shown. The history
- * view's animation will be deferred until all the {@link TaskView}s are finished animating.
+ * Starts the animation to hide the {@link TaskView}s when the history is shown.
*/
public void startShowHistoryAnimation(ReferenceCountedTrigger postAnimationTrigger) {
Resources res = mStackView.getResources();
TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
TaskStackViewScroller stackScroller = mStackView.getScroller();
+ int offscreenY = stackLayout.mStackRect.bottom;
int historyTransitionDuration = res.getInteger(
R.integer.recents_history_transition_duration);
+ int startDelayIncr = 16;
List<TaskView> taskViews = mStackView.getTaskViews();
int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
- TaskViewAnimation taskAnimation = new TaskViewAnimation(
- historyTransitionDuration, PhoneStatusBar.ALPHA_OUT,
+ TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
+ historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
mTmpTransform.alpha = 0f;
+ mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
}
/**
- * Starts the animation to show the {@link TaskView}s when the history is hidden. The
- * {@link TaskView} animations will be deferred until the history view has been animated away.
+ * Starts the animation to show the {@link TaskView}s when the history is hidden.
*/
- public void startHideHistoryAnimation(final ReferenceCountedTrigger postAnimationTrigger) {
- final Resources res = mStackView.getResources();
- final TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- final TaskStackViewScroller stackScroller = mStackView.getScroller();
+ public void startHideHistoryAnimation() {
+ Resources res = mStackView.getResources();
+ TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+ TaskStackViewScroller stackScroller = mStackView.getScroller();
- final int historyTransitionDuration = res.getInteger(
+ int historyTransitionDuration = res.getInteger(
R.integer.recents_history_transition_duration);
+ int startDelayIncr = 16;
List<TaskView> taskViews = mStackView.getTaskViews();
int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) {
- final TaskView tv = taskViews.get(i);
- postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
- @Override
- public void run() {
- TaskViewAnimation taskAnimation = new TaskViewAnimation(
- historyTransitionDuration, PhoneStatusBar.ALPHA_IN);
- stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
- mTmpTransform, null);
- mTmpTransform.alpha = 1f;
- mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
- }
- });
+ TaskView tv = taskViews.get(i);
+ TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
+ historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN);
+ stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
+ mTmpTransform, null);
+ mTmpTransform.alpha = 1f;
+ mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 93849dc..7c695ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -25,8 +25,8 @@
import android.util.ArraySet;
import android.util.FloatProperty;
import android.util.Property;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -212,7 +212,6 @@
}
Context mContext;
- private Interpolator mLinearOutSlowInInterpolator;
private StackState mState = StackState.SPLIT;
private TaskStackLayoutAlgorithmCallbacks mCb;
@@ -299,8 +298,6 @@
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
}
/**
@@ -354,6 +351,7 @@
mStackBottomOffset = mSystemInsets.bottom + heightPadding;
state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding,
mStackBottomOffset);
+ // The history button will take the full un-padded header space above the stack
mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding,
mStackRect.right, mStackRect.top + mFocusedPeekHeight);
@@ -488,7 +486,7 @@
newState);
mFocusStateAnimator.setDuration(mContext.getResources().getInteger(
R.integer.recents_animate_task_stack_scroll_duration));
- mFocusStateAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+ mFocusStateAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mFocusStateAnimator.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 7423b78..232b416 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -36,9 +36,10 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -58,6 +59,7 @@
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
@@ -74,6 +76,7 @@
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
import com.android.systemui.recents.misc.DozeTrigger;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -140,6 +143,7 @@
Rect mStableStackBounds = new Rect();
// The current stack bounds are dynamic and may change as the user drags and drops
Rect mStackBounds = new Rect();
+
int[] mTmpVisibleRange = new int[2];
Rect mTmpRect = new Rect();
ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
@@ -147,8 +151,6 @@
TaskViewTransform mTmpTransform = new TaskViewTransform();
LayoutInflater mInflater;
- Interpolator mFastOutSlowInInterpolator;
-
// A convenience update listener to request updating clipping of tasks
private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
new ValueAnimator.AnimatorUpdateListener() {
@@ -199,8 +201,6 @@
mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
mAnimationHelper = new TaskStackAnimationHelper(context, this);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
mTaskCornerRadiusPx = res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
mDividerSize = ssp.getDockedDividerSize(context);
@@ -233,8 +233,8 @@
@Override
protected void onAttachedToWindow() {
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
- readSystemFlags();
super.onAttachedToWindow();
+ readSystemFlags();
}
@Override
@@ -862,8 +862,7 @@
// TODO: Center the newly focused task view, only if not freeform
float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask);
if (Float.compare(newScroll, mStackScroller.getStackScroll()) != 0) {
- mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
- focusTaskRunnable);
+ mStackScroller.animateScroll(newScroll, focusTaskRunnable);
willScroll = true;
} else {
focusTaskRunnable.run();
@@ -1117,12 +1116,19 @@
// We can get spurious measure passes with the old bounds when docking, and since we are
// using the current stack bounds during drag and drop, don't overwrite them until we
// actually get new bounds
+ boolean requiresLayout = false;
if (!taskStackBounds.equals(mStableStackBounds)) {
mStableStackBounds.set(taskStackBounds);
mStackBounds.set(taskStackBounds);
+ requiresLayout = true;
}
- mLayoutAlgorithm.setSystemInsets(systemInsets);
- requestLayout();
+ if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
+ mLayoutAlgorithm.setSystemInsets(systemInsets);
+ requiresLayout = true;
+ }
+ if (requiresLayout) {
+ requestLayout();
+ }
}
/**
@@ -1219,7 +1225,7 @@
// Animate in the freeform workspace
animateFreeformWorkspaceBackgroundAlpha(
mLayoutAlgorithm.getStackState().freeformBackgroundAlpha, 150,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
// Set the task focused state without requesting view focus, and leave the focus animations
// until after the enter-animation
@@ -1235,7 +1241,7 @@
// Update the history button visibility
if (shouldShowHistoryButton() &&
mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new ShowHistoryButtonEvent());
+ EventBus.getDefault().send(new ShowHistoryButtonEvent(false /* translate */));
} else {
EventBus.getDefault().send(new HideHistoryButtonEvent());
}
@@ -1313,7 +1319,7 @@
// Animate all the tasks into place
relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
}
/**
@@ -1409,10 +1415,12 @@
tv.onTaskBound(task);
// Load the task data
- Recents.getTaskLoader().loadTaskData(task);
+ Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
// If the doze trigger has already fired, then update the state for this task view
- tv.setNoUserInteractionState();
+ if (mUIDozeTrigger.hasTriggered()) {
+ tv.setNoUserInteractionState();
+ }
// Set the new state for this view, including the callbacks and view clipping
tv.setCallbacks(this);
@@ -1468,13 +1476,15 @@
relayoutTaskViewsOnNextFrame(animation);
}
- if (shouldShowHistoryButton() &&
- prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
- curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new ShowHistoryButtonEvent());
- } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
- curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new HideHistoryButtonEvent());
+ if (mEnterAnimationComplete) {
+ if (shouldShowHistoryButton() &&
+ prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+ curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+ EventBus.getDefault().send(new ShowHistoryButtonEvent(true /* translate */));
+ } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+ curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+ EventBus.getDefault().send(new HideHistoryButtonEvent());
+ }
}
}
@@ -1524,7 +1534,7 @@
int taskViewExitToHomeDuration = getResources().getInteger(
R.integer.recents_task_exit_to_home_duration);
animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
}
public final void onBusEvent(DismissFocusedTaskViewEvent event) {
@@ -1579,8 +1589,7 @@
public final void onBusEvent(DragStartEvent event) {
if (event.task.isFreeformTask()) {
// Animate to the front of the stack
- mStackScroller.animateScroll(mStackScroller.getStackScroll(),
- mLayoutAlgorithm.mInitialScrollP, null);
+ mStackScroller.animateScroll(mLayoutAlgorithm.mInitialScrollP, null);
}
// Enlarge the dragged view slightly
@@ -1590,7 +1599,7 @@
mTmpTransform.scale = finalScale;
mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
updateTaskViewToTransform(event.taskView, mTmpTransform,
- new TaskViewAnimation(DRAG_SCALE_DURATION, mFastOutSlowInInterpolator));
+ new TaskViewAnimation(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN));
}
public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
@@ -1602,11 +1611,10 @@
}
public final void onBusEvent(DragDropTargetChangedEvent event) {
- TaskViewAnimation animation = new TaskViewAnimation(250, mFastOutSlowInInterpolator);
+ TaskViewAnimation animation = new TaskViewAnimation(250, Interpolators.FAST_OUT_SLOW_IN);
if (event.dropTarget instanceof TaskStack.DockState) {
// Calculate the new task stack bounds that matches the window size that Recents will
// have after the drop
- addIgnoreTask(event.task);
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
@@ -1676,9 +1684,9 @@
mTmpTransform, null);
event.getAnimationTrigger().increment();
relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
updateTaskViewToTransform(event.taskView, mTmpTransform,
- new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, mFastOutSlowInInterpolator,
+ new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
event.getAnimationTrigger().decrementOnAnimationEnd()));
removeIgnoreTask(event.task);
}
@@ -1753,11 +1761,30 @@
}
public final void onBusEvent(ShowHistoryEvent event) {
- mAnimationHelper.startShowHistoryAnimation(event.getAnimationTrigger());
+ ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
+ postAnimTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(View.INVISIBLE);
+ }
+ });
+ mAnimationHelper.startShowHistoryAnimation(postAnimTrigger);
}
public final void onBusEvent(HideHistoryEvent event) {
- mAnimationHelper.startHideHistoryAnimation(event.getAnimationTrigger());
+ setVisibility(View.VISIBLE);
+ mAnimationHelper.startHideHistoryAnimation();
+ }
+
+ public final void onBusEvent(TaskStackUpdatedEvent event) {
+ // Scroll the stack to the front after it has been updated
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
+ null /* postScrollRunnable */);
+ }
+ });
}
/**
@@ -1771,7 +1798,7 @@
// Remove the task from the stack
mStack.removeTask(task, new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 4ec051f..ced5d4b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -23,10 +23,12 @@
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.OverScroller;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
/* The scrolling logic for a TaskStackView */
@@ -69,16 +71,12 @@
ObjectAnimator mScrollAnimator;
float mFinalAnimatedScroll;
- private Interpolator mLinearOutSlowInInterpolator;
-
public TaskStackViewScroller(Context context, TaskStackViewScrollerCallbacks cb,
TaskStackLayoutAlgorithm layoutAlgorithm) {
mContext = context;
mCb = cb;
mScroller = new OverScroller(context);
mLayoutAlgorithm = layoutAlgorithm;
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
}
/** Resets the task scroller. */
@@ -115,8 +113,13 @@
* @return whether the stack progress changed.
*/
public boolean setStackScrollToInitialState() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
float prevStackScrollP = mStackScrollP;
- setStackScroll(getBoundedStackScroll(mLayoutAlgorithm.mInitialScrollP));
+ if (ssp.hasDockedTask()) {
+ setStackScroll(mLayoutAlgorithm.mMaxScrollP);
+ } else {
+ setStackScroll(mLayoutAlgorithm.mInitialScrollP);
+ }
return Float.compare(prevStackScrollP, mStackScrollP) != 0;
}
@@ -173,13 +176,13 @@
float newScroll = getBoundedStackScroll(curScroll);
if (Float.compare(newScroll, curScroll) != 0) {
// Start a new scroll animation
- animateScroll(curScroll, newScroll, null);
+ animateScroll(newScroll, null /* postScrollRunnable */);
}
return mScrollAnimator;
}
/** Animates the stack scroll */
- void animateScroll(float curScroll, float newScroll, final Runnable postRunnable) {
+ void animateScroll(float newScroll, final Runnable postRunnable) {
// Finish any current scrolling animations
if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
setStackScroll(mFinalAnimatedScroll);
@@ -189,10 +192,10 @@
stopBoundScrollAnimation();
mFinalAnimatedScroll = newScroll;
- mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, curScroll, newScroll);
+ mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, getStackScroll(), newScroll);
mScrollAnimator.setDuration(mContext.getResources().getInteger(
R.integer.recents_animate_task_stack_scroll_duration));
- mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+ mScrollAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mScrollAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index e9f6f39..da99956 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -31,7 +31,9 @@
import android.view.ViewParent;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.recents.Constants;
@@ -121,7 +123,7 @@
@Override
protected void prepareSnapBackAnimation(View v, Animator anim) {
- anim.setInterpolator(mSv.mFastOutSlowInInterpolator);
+ anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mSwipeHelperAnimations.put(v, anim);
}
};
@@ -215,8 +217,11 @@
case MotionEvent.ACTION_MOVE: {
int activePointerIndex = ev.findPointerIndex(mActivePointerId);
int y = (int) ev.getY(activePointerIndex);
+ int x = (int) ev.getX(activePointerIndex);
if (!mIsScrolling) {
- if (Math.abs(y - mDownY) > mScrollTouchSlop) {
+ int yDiff = Math.abs(y - mDownY);
+ int xDiff = Math.abs(x - mDownX);
+ if (Math.abs(y - mDownY) > mScrollTouchSlop && yDiff > xDiff) {
mIsScrolling = true;
// Disallow parents from intercepting touch events
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 5a4064a..853f868 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -29,6 +29,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -37,8 +38,8 @@
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -54,7 +55,6 @@
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
@@ -115,6 +115,7 @@
Task mTask;
boolean mTaskDataLoaded;
boolean mClipViewInStack = true;
+ boolean mTouchExplorationEnabled;
AnimateableViewBounds mViewBounds;
private AnimatorSet mTransformAnimation;
@@ -128,8 +129,6 @@
Point mDownTouchPos = new Point();
- Interpolator mFastOutSlowInInterpolator;
-
public TaskView(Context context) {
this(context, null);
}
@@ -149,8 +148,6 @@
mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius));
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
if (config.fakeShadows) {
setBackground(new FakeShadowDrawable(res, config));
}
@@ -167,6 +164,7 @@
void reset() {
resetViewProperties();
resetNoUserInteractionState();
+ readSystemFlags();
setClipViewInStack(false);
setCallbacks(null);
}
@@ -182,6 +180,12 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ readSystemFlags();
+ }
+
+ @Override
protected void onFinishInflate() {
// Bind the views
mContent = findViewById(R.id.task_view_content);
@@ -456,7 +460,7 @@
.scaleX(1f)
.scaleY(1f)
.setDuration(fadeInDuration)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .setInterpolator(Interpolators.ALPHA_IN)
.start();
} else {
mActionButtonView.setScaleX(1f);
@@ -483,7 +487,7 @@
mActionButtonView.animate()
.alpha(0f)
.setDuration(fadeOutDuration)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -529,7 +533,7 @@
if (mDimAlpha > 0) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
anim.setDuration(duration);
- anim.setInterpolator(PhoneStatusBar.ALPHA_OUT);
+ anim.setInterpolator(Interpolators.ALPHA_OUT);
anim.start();
}
@@ -550,7 +554,7 @@
public void onTaskDataLoaded(Task task) {
// Bind each of the views to the new task data
mThumbnailView.rebindToTask(mTask);
- mHeaderView.rebindToTask(mTask);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
mTaskDataLoaded = true;
}
@@ -559,13 +563,13 @@
// Unbind each of the views from the task data and remove the task callback
mTask.removeCallback(this);
mThumbnailView.unbindFromTask();
- mHeaderView.unbindFromTask();
+ mHeaderView.unbindFromTask(mTouchExplorationEnabled);
mTaskDataLoaded = false;
}
@Override
public void onTaskStackIdChanged() {
- mHeaderView.rebindToTask(mTask);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
}
/**** View.OnClickListener Implementation ****/
@@ -620,4 +624,12 @@
}
EventBus.getDefault().unregister(this);
}
+
+ /**
+ * Reads current system flags related to accessibility and screen pinning.
+ */
+ private void readSystemFlags() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
index 363ad66..5455042 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
@@ -19,7 +19,8 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
+
+import com.android.systemui.Interpolators;
import java.util.List;
@@ -29,7 +30,7 @@
public class TaskViewAnimation {
public static final TaskViewAnimation IMMEDIATE = new TaskViewAnimation(0,
- new LinearInterpolator());
+ Interpolators.LINEAR);
public final int startDelay;
public final int duration;
@@ -45,6 +46,10 @@
this(0 /* startDelay */, duration, interpolator, listener);
}
+ public TaskViewAnimation(int startDelay, int duration, Interpolator interpolator) {
+ this(startDelay, duration, interpolator, null);
+ }
+
public TaskViewAnimation(int startDelay, int duration, Interpolator interpolator,
Animator.AnimatorListener listener) {
this.startDelay = startDelay;
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 d5aea9d..5e17b90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -37,17 +37,16 @@
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewStub;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
@@ -164,10 +163,6 @@
// Header dim, which is only used when task view hardware layers are not used
private Paint mDimLayerPaint = new Paint();
- Interpolator mFastOutSlowInInterpolator;
- Interpolator mFastOutLinearInInterpolator;
- Interpolator mLinearOutSlowInInterpolator;
-
private CountDownTimer mFocusTimerCountDown;
public TaskViewHeader(Context context) {
@@ -201,13 +196,6 @@
mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
-
// Configure the background and dim
mBackground = new HighlightColorDrawable();
mBackground.setColorAndDim(Color.argb(255, 0, 0, 0), 0f);
@@ -226,14 +214,18 @@
@Override
protected void onFinishInflate() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+
// Initialize the icon and description views
mIconView = (ImageView) findViewById(R.id.icon);
mIconView.setClickable(false);
mIconView.setOnLongClickListener(this);
mTitleView = (TextView) findViewById(R.id.title);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
- mDismissButton.setOnClickListener(this);
- mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
+ if (ssp.hasFreeformWorkspaceSupport()) {
+ mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ }
mFocusTimerIndicatorStub = (ViewStub) findViewById(R.id.focus_timer_indicator_stub);
mAppOverlayViewStub = (ViewStub) findViewById(R.id.app_overlay_stub);
}
@@ -351,7 +343,6 @@
void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
updateBackgroundColor(dimAlpha);
- invalidate();
}
/**
@@ -365,11 +356,12 @@
mTmpHSL[2] = Math.min(1f, mTmpHSL[2] + OVERLAY_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
mOverlayBackground.setColorAndDim(ColorUtils.HSLToColor(mTmpHSL), dimAlpha);
mDimLayerPaint.setAlpha((int) (dimAlpha * 255));
+ invalidate();
}
}
/** Binds the bar view to the task */
- public void rebindToTask(Task t) {
+ public void rebindToTask(Task t, boolean touchExplorationEnabled) {
SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
@@ -403,10 +395,6 @@
? mLightFreeformIcon
: mDarkFreeformIcon);
}
- if (mMoveTaskButton.getVisibility() != View.VISIBLE) {
- mMoveTaskButton.setVisibility(View.VISIBLE);
- }
- mMoveTaskButton.setOnClickListener(this);
}
if (Recents.getDebugFlags().isFastToggleRecentsEnabled()) {
@@ -420,32 +408,37 @@
}
// In accessibility, a single click on the focused app info button will show it
- if (ssp.isTouchExplorationEnabled()) {
+ if (touchExplorationEnabled) {
mIconView.setOnClickListener(this);
}
}
/** Unbinds the bar view from the task */
- void unbindFromTask() {
+ void unbindFromTask(boolean touchExplorationEnabled) {
mTask = null;
mIconView.setImageDrawable(null);
- mIconView.setOnClickListener(null);
- mMoveTaskButton.setOnClickListener(null);
+ if (touchExplorationEnabled) {
+ mIconView.setOnClickListener(null);
+ }
}
/** Animates this task bar if the user does not interact with the stack after a certain time. */
void startNoUserInteractionAnimation() {
- if (mDismissButton.getVisibility() != View.VISIBLE) {
- mDismissButton.setVisibility(View.VISIBLE);
- mDismissButton.setAlpha(0f);
- mDismissButton.animate()
- .alpha(1f)
- .setStartDelay(0)
- .setInterpolator(mFastOutLinearInInterpolator)
- .setDuration(getResources().getInteger(
- R.integer.recents_task_enter_from_app_duration))
- .start();
- }
+ int duration = getResources().getInteger(R.integer.recents_task_enter_from_app_duration);
+ mDismissButton.setOnClickListener(this);
+ mDismissButton.setVisibility(View.VISIBLE);
+ mDismissButton.animate()
+ .alpha(1f)
+ .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
+ .setDuration(duration)
+ .start();
+ mMoveTaskButton.setOnClickListener(this);
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ mMoveTaskButton.animate()
+ .alpha(1f)
+ .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
+ .setDuration(duration)
+ .start();
}
/**
@@ -453,11 +446,14 @@
* time.
*/
void setNoUserInteractionState() {
- if (mDismissButton.getVisibility() != View.VISIBLE) {
- mDismissButton.animate().cancel();
- mDismissButton.setVisibility(View.VISIBLE);
- mDismissButton.setAlpha(1f);
- }
+ mDismissButton.setVisibility(View.VISIBLE);
+ mDismissButton.animate().cancel();
+ mDismissButton.setAlpha(1f);
+ mDismissButton.setOnClickListener(this);
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ mMoveTaskButton.animate().cancel();
+ mMoveTaskButton.setAlpha(1f);
+ mMoveTaskButton.setOnClickListener(this);
}
/**
@@ -466,6 +462,11 @@
*/
void resetNoUserInteractionState() {
mDismissButton.setVisibility(View.INVISIBLE);
+ mDismissButton.setAlpha(0f);
+ mDismissButton.setOnClickListener(null);
+ mMoveTaskButton.setVisibility(View.INVISIBLE);
+ mMoveTaskButton.setAlpha(0f);
+ mMoveTaskButton.setOnClickListener(null);
}
@Override
@@ -479,11 +480,8 @@
@Override
public void onClick(View v) {
if (v == mIconView) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.isTouchExplorationEnabled()) {
- // In accessibility, a single click on the focused app info button will show it
- EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
- }
+ // In accessibility, a single click on the focused app info button will show it
+ EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
} else if (v == mDismissButton) {
TaskView tv = Utilities.findParent(this, TaskView.class);
tv.dismissTask();
@@ -558,7 +556,7 @@
Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y, 0,
getWidth());
revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
- revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+ revealAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
revealAnim.start();
}
@@ -579,7 +577,7 @@
Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y,
getWidth(), 0);
revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
- revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+ revealAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
revealAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index de96d9d..f90951e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -27,11 +27,8 @@
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.util.Property;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
@@ -54,8 +51,6 @@
BitmapShader mBitmapShader;
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
- Interpolator mFastOutSlowInInterpolator;
-
// Task bar clipping, the top of this thumbnail can be clipped against the opaque header
// bar that overlaps this thumbnail
View mTaskBar;
@@ -84,8 +79,6 @@
mDrawPaint.setAntiAlias(true);
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
}
/**
@@ -100,7 +93,6 @@
mTaskViewRect.set(0, 0, width, height);
updateThumbnailScale();
- invalidate();
}
@Override
@@ -127,7 +119,6 @@
mDrawPaint.setShader(null);
mThumbnailRect.setEmpty();
}
- invalidate();
}
/** Updates the paint to draw the thumbnail. */
@@ -145,7 +136,9 @@
mDrawPaint.setColorFilter(null);
mDrawPaint.setColor(Color.argb(255, grey, grey, grey));
}
- invalidate();
+ if (!mInvisible) {
+ invalidate();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 77c27fa..d5131be 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -31,6 +31,7 @@
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import java.util.ArrayList;
@@ -205,7 +206,7 @@
if (!mAutomatic) {
final int val = value + mMinimumBacklight;
if (stopTracking) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS, val);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
}
setBrightness(val);
if (!tracking) {
@@ -220,7 +221,7 @@
} else {
final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
if (stopTracking) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS_AUTO, value);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
}
setBrightnessAdj(adj);
if (!tracking) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index cef4d34..4952234 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -25,6 +25,7 @@
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
/** A dialog that provides controls for adjusting the screen brightness. */
@@ -53,13 +54,13 @@
protected void onStart() {
super.onStart();
mBrightnessController.registerCallbacks();
- MetricsLogger.visible(this, MetricsLogger.BRIGHTNESS_DIALOG);
+ MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}
@Override
protected void onStop() {
super.onStop();
- MetricsLogger.hidden(this, MetricsLogger.BRIGHTNESS_DIALOG);
+ MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
mBrightnessController.unregisterCallbacks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index d8a202c..dd80750 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.UserHandle;
public abstract class CurrentUserTracker extends BroadcastReceiver {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
index 8829794..722aba5 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.SeekBar;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c0e1e44..0b20f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -46,9 +46,9 @@
import android.widget.FrameLayout;
import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -73,8 +73,6 @@
private static final String TAG = "DividerView";
private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
- private static final float DIM_START_FRACTION = 0.5f;
- private static final float DIM_DAMP_FACTOR = 1.7f;
/**
* Fraction of the divider position between two snap targets to switch to the full-screen
@@ -90,6 +88,8 @@
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+ private static final PathInterpolator DIM_INTERPOLATOR =
+ new PathInterpolator(.23f, .87f, .52f, -0.11f);
private DividerHandleView mHandle;
private View mBackground;
@@ -497,8 +497,8 @@
mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
}
float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
- fraction = Math.max(0,
- Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f));
+ fraction = Math.max(0, Math.min(fraction, 1f));
+ fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
fraction);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 67bb58a..24ab506 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -97,7 +97,8 @@
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true);
+ ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false,
+ false);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 01bfcea..874defa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -32,6 +32,7 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 90f7c08..7670223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -21,7 +21,6 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageView;
import android.widget.RemoteViews.RemoteView;
@RemoteView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index efa56bc..333e4ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.Notification;
@@ -76,18 +75,19 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
@@ -826,30 +826,25 @@
}
}
- protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
+ protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
- if (n.isClearable()) {
- final String _pkg = n.getPackageName();
- final String _tag = n.getTag();
- final int _id = n.getId();
- final int _userId = n.getUserId();
- vetoButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- // Accessibility feedback
- v.announceForAccessibility(
- mContext.getString(R.string.accessibility_notification_dismissed));
- try {
- mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+ final String _pkg = n.getPackageName();
+ final String _tag = n.getTag();
+ final int _id = n.getId();
+ final int _userId = n.getUserId();
+ vetoButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ // Accessibility feedback
+ v.announceForAccessibility(
+ mContext.getString(R.string.accessibility_notification_dismissed));
+ try {
+ mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- }
- });
- vetoButton.setVisibility(View.VISIBLE);
- } else {
- vetoButton.setVisibility(View.GONE);
- }
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ }
+ });
vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
return vetoButton;
}
@@ -947,7 +942,7 @@
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_INFO);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
startAppNotificationSettingsActivity(pkg, appUidF);
}
});
@@ -994,7 +989,7 @@
return false;
}
- MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
// ensure that it's layouted but not visible until actually laid out
guts.setVisibility(View.INVISIBLE);
@@ -1173,7 +1168,7 @@
}
protected void toggleKeyboardShortcuts() {
- getKeyboardShortcuts().toggleKeyboardShortcuts(mContext);
+ getKeyboardShortcuts().toggleKeyboardShortcuts();
}
protected void cancelPreloadingRecents() {
@@ -1223,10 +1218,7 @@
final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
- userHandle);
- final boolean allowedByDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+ final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
final boolean allowed = allowedByUser && allowedByDpm;
mUsersAllowingPrivateNotifications.append(userHandle, allowed);
return allowed;
@@ -1235,6 +1227,15 @@
return mUsersAllowingPrivateNotifications.get(userHandle);
}
+ private boolean adminAllowsUnredactedNotifications(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+ final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
+ userHandle);
+ return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+ }
+
/**
* Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
* notification data. If so, private notifications should show their (possibly
@@ -1362,7 +1363,7 @@
}
workAroundBadLayerDrawableOpacity(row);
- View vetoButton = updateNotificationVetoButton(row, sbn);
+ View vetoButton = bindVetoButtonClickListener(row, sbn);
vetoButton.setContentDescription(mContext.getString(
R.string.accessibility_remove_notification));
@@ -1510,7 +1511,7 @@
protected KeyboardShortcuts getKeyboardShortcuts() {
if (mKeyboardShortcuts == null) {
- mKeyboardShortcuts = new KeyboardShortcuts();
+ mKeyboardShortcuts = new KeyboardShortcuts(mContext);
}
return mKeyboardShortcuts;
@@ -2002,7 +2003,7 @@
// Update the veto button accordingly (and as a result, whether this row is
// swipe-dismissable)
- updateNotificationVetoButton(entry.row, notification);
+ bindVetoButtonClickListener(entry.row, notification);
if (DEBUG) {
// Is this for you?
@@ -2045,6 +2046,21 @@
entry.row.resetHeight();
}
+ protected void updatePublicContentView(Entry entry,
+ StatusBarNotification sbn) {
+ final RemoteViews publicContentView = entry.cachedPublicContentView;
+ if (publicContentView != null && entry.getPublicContentView() != null) {
+ final boolean disabledByPolicy =
+ !adminAllowsUnredactedNotifications(entry.notification.getUserId());
+ publicContentView.setTextViewText(android.R.id.title,
+ mContext.getString(disabledByPolicy
+ ? com.android.internal.R.string.notification_hidden_by_policy_text
+ : com.android.internal.R.string.notification_hidden_text));
+ publicContentView.reapply(sbn.getPackageContext(mContext),
+ entry.getPublicContentView(), mOnClickHandler);
+ }
+ }
+
protected void notifyHeadsUpScreenOff() {
maybeEscalateHeadsUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index cc26223..60fc0fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,6 +21,7 @@
import android.os.IBinder;
import android.os.Message;
import android.util.Pair;
+
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 24cd948..212d290 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,7 +18,7 @@
import android.view.View;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.Interpolators;
/**
* A helper to fade views in and out.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
index a323684..46060f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 5c83f5f..b326552 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -27,6 +27,7 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6fae3ab..7f1316f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -28,7 +28,6 @@
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Chronometer;
@@ -212,7 +211,8 @@
mStatusBarNotification = entry.notification;
mPrivateLayout.onNotificationUpdated(entry);
mPublicLayout.onNotificationUpdated(entry);
- updateVetoButton();
+ mShowingPublicInitialized = false;
+ updateClearability();
if (mIsSummaryWithChildren) {
recreateNotificationHeader();
}
@@ -911,7 +911,7 @@
}
mPrivateLayout.updateExpandButtons(isExpandable());
- updateVetoButton();
+ updateClearability();
mShowingPublicInitialized = true;
}
@@ -947,7 +947,7 @@
}
}
- private void updateVetoButton() {
+ private void updateClearability() {
// public versions cannot be dismissed
mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index c4ffd7f..bddd3e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -22,6 +22,8 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.Interpolators;
+
/**
* Utility class to calculate general fling animation when the finger is released.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index b36fb7e..963920c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -19,25 +19,30 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
import android.os.Handler;
-import android.util.Log;
+import android.os.Looper;
+import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup.LayoutParams;
import android.view.Window;
-import android.view.WindowManager;
import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
+import java.util.ArrayList;
import java.util.List;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.graphics.Color.TRANSPARENT;
import static android.view.Gravity.TOP;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -45,33 +50,44 @@
* Contains functionality for handling keyboard shortcuts.
*/
public class KeyboardShortcuts {
- private static final String TAG = "KeyboardShortcuts";
+ private static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386';
+ private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F';
+ private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009';
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Context mContext;
+ private final OnClickListener dialogCloseListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dismissKeyboardShortcutsDialog();
+ }
+ };
private Dialog mKeyboardShortcutsDialog;
- public KeyboardShortcuts() {}
+ public KeyboardShortcuts(Context context) {
+ this.mContext = context;
+ }
- public void toggleKeyboardShortcuts(final Context context) {
+ public void toggleKeyboardShortcuts() {
if (mKeyboardShortcutsDialog == null) {
- Recents.getSystemServices().requestKeyboardShortcuts(context,
+ Recents.getSystemServices().requestKeyboardShortcuts(mContext,
new KeyboardShortcutsReceiver() {
@Override
public void onKeyboardShortcutsReceived(
final List<KeyboardShortcutGroup> result) {
KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
- context.getString(R.string.keyboard_shortcut_group_system));
+ mContext.getString(R.string.keyboard_shortcut_group_system), true);
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_home),
- '\u2386', KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_home),
+ SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_back),
- '\u007F', KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_back),
+ SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_recents),
- '\u0009', KeyEvent.META_ALT_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_recents),
+ SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON));
result.add(systemGroup);
- Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result));
- showKeyboardShortcutsDialog(context);
+ showKeyboardShortcutsDialog(result);
}
});
} else {
@@ -79,33 +95,6 @@
}
}
- private void showKeyboardShortcutsDialog(Context context) {
- // Create dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- LAYOUT_INFLATER_SERVICE);
- final View keyboardShortcutsView = inflater.inflate(
- R.layout.keyboard_shortcuts_view, null);
-
- populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_wrapper));
- dialogBuilder.setView(keyboardShortcutsView);
- mKeyboardShortcutsDialog = dialogBuilder.create();
- mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
-
- // Setup window.
- Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
- keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
- keyboardShortcutsWindow.setBackgroundDrawable(
- new ColorDrawable(TRANSPARENT));
- keyboardShortcutsWindow.setGravity(TOP);
- keyboardShortcutsView.post(new Runnable() {
- public void run() {
- mKeyboardShortcutsDialog.show();
- }
- });
- }
-
public void dismissKeyboardShortcutsDialog() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
@@ -113,11 +102,99 @@
}
}
- /**
- * @return {@code true} if the keyboard shortcuts have been successfully populated.
- */
- private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) {
- // TODO: Populate shortcuts.
- return true;
+ private void showKeyboardShortcutsDialog(
+ final List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ // Need to post on the main thread.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // TODO: break all this code out into a handleShowKeyboard...
+ // Might add more things posted; should consider adding a custom handler so
+ // you can send the keyboardShortcutsGroups as part of the message.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ LAYOUT_INFLATER_SERVICE);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_view, null);
+ DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+ ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_scroll_view);
+ // TODO: find a better way to set the height.
+ scrollView.setLayoutParams(new LinearLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT,
+ (int) (dm.heightPixels * dm.density)));
+
+ populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
+ dialogBuilder.setView(keyboardShortcutsView);
+ dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+ mKeyboardShortcutsDialog = dialogBuilder.create();
+ mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+ // Setup window.
+ Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ keyboardShortcutsWindow.setBackgroundDrawable(
+ mContext.getDrawable(R.color.ksh_dialog_background_color));
+ keyboardShortcutsWindow.setGravity(TOP);
+ mKeyboardShortcutsDialog.show();
+ }
+ });
+ }
+
+ private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout,
+ List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ final int keyboardShortcutGroupsSize = keyboardShortcutGroups.size();
+ for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+ KeyboardShortcutGroup group = keyboardShortcutGroups.get(i);
+ TextView categoryTitle = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+ categoryTitle.setText(group.getLabel());
+ categoryTitle.setTextColor(group.isSystemGroup()
+ ? mContext.getColor(R.color.ksh_system_group_color)
+ : mContext.getColor(R.color.ksh_application_group_color));
+ keyboardShortcutsLayout.addView(categoryTitle);
+
+ LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_wrapper, null);
+ final int itemsSize = group.getItems().size();
+ for (int j = 0; j < itemsSize; j++) {
+ KeyboardShortcutInfo info = group.getItems().get(j);
+ View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null);
+ TextView textView = (TextView) shortcutView
+ .findViewById(R.id.keyboard_shortcuts_keyword);
+ textView.setText(info.getLabel());
+
+ List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+ final int shortcutKeysSize = shortcutKeys.size();
+ for (int k = 0; k < shortcutKeysSize; k++) {
+ String shortcutKey = shortcutKeys.get(k);
+ TextView shortcutKeyView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_view, null);
+ shortcutKeyView.setText(shortcutKey);
+ LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+ .findViewById(R.id.keyboard_shortcuts_item_container);
+ shortcutItemsContainer.addView(shortcutKeyView);
+ }
+ shortcutWrapper.addView(shortcutView);
+ }
+
+ // TODO: merge container and wrapper into one xml file - wrapper is always a child of
+ // container.
+ LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_container, null);
+ shortcutsContainer.addView(shortcutWrapper);
+ keyboardShortcutsLayout.addView(shortcutsContainer);
+ }
+ }
+
+ private List<String> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+ // TODO: fix the shortcuts. Find or build an util which can produce human readable
+ // names of the baseCharacter and the modifiers.
+ List<String> shortcutKeys = new ArrayList<>();
+ shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase());
+ shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase());
+ return shortcutKeys;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 841b9d0..0b1984d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -36,6 +36,7 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 635e66d..00b9888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -19,7 +19,6 @@
import android.app.Notification;
import android.app.RemoteInput;
import android.content.Context;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Build;
import android.service.notification.StatusBarNotification;
@@ -27,7 +26,6 @@
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
@@ -53,6 +51,7 @@
private final Rect mClipBounds = new Rect();
private final int mMinContractedHeight;
+ private final int mNotificationContentMarginEnd;
private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -109,6 +108,8 @@
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
+ mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
reset(true);
}
@@ -128,6 +129,19 @@
maxSize = MeasureSpec.getSize(heightMeasureSpec);
}
int maxChildHeight = 0;
+ if (mExpandedChild != null) {
+ int size = Math.min(maxSize, mNotificationMaxHeight);
+ ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
+ if (layoutParams.height >= 0) {
+ // An actual height is set
+ size = Math.min(maxSize, layoutParams.height);
+ }
+ int spec = size == Integer.MAX_VALUE
+ ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+ : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ mExpandedChild.measure(widthMeasureSpec, spec);
+ maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
+ }
if (mContractedChild != null) {
int heightSpec;
if (shouldContractedBeFixedSize()) {
@@ -143,19 +157,9 @@
mContractedChild.measure(widthMeasureSpec, heightSpec);
}
maxChildHeight = Math.max(maxChildHeight, measuredHeight);
- }
- if (mExpandedChild != null) {
- int size = Math.min(maxSize, mNotificationMaxHeight);
- ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
- if (layoutParams.height >= 0) {
- // An actual height is set
- size = Math.min(maxSize, layoutParams.height);
+ if (updateContractedHeaderWidth()) {
+ mContractedChild.measure(widthMeasureSpec, heightSpec);
}
- int spec = size == Integer.MAX_VALUE
- ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
- mExpandedChild.measure(widthMeasureSpec, spec);
- maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
}
if (mHeadsUpChild != null) {
int size = Math.min(maxSize, mHeadsUpHeight);
@@ -178,6 +182,44 @@
setMeasuredDimension(width, ownHeight);
}
+ private boolean updateContractedHeaderWidth() {
+ // We need to update the expanded and the collapsed header to have exactly the same with to
+ // have the expand buttons laid out at the same location.
+ NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
+ if (contractedHeader != null) {
+ if (mExpandedChild != null
+ && mExpandedWrapper.getNotificationHeader() != null) {
+ NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
+ int expandedSize = expandedHeader.getMeasuredWidth()
+ - expandedHeader.getPaddingEnd();
+ int collapsedSize = contractedHeader.getMeasuredWidth()
+ - expandedHeader.getPaddingEnd();
+ if (expandedSize != collapsedSize) {
+ int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
+ contractedHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+ contractedHeader.getPaddingTop(),
+ isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+ contractedHeader.getPaddingBottom());
+ contractedHeader.setShowWorkBadgeAtEnd(true);
+ return true;
+ }
+ } else {
+ int paddingEnd = mNotificationContentMarginEnd;
+ if (contractedHeader.getPaddingEnd() != paddingEnd) {
+ contractedHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+ contractedHeader.getPaddingTop(),
+ isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+ contractedHeader.getPaddingBottom());
+ contractedHeader.setShowWorkBadgeAtEnd(false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private boolean shouldContractedBeFixedSize() {
return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
}
@@ -460,16 +502,16 @@
if (mDark == dark || mContractedChild == null) return;
mDark = dark;
dark = dark && !mShowingLegacyBackground;
- if (mVisibleType == VISIBLE_TYPE_CONTRACTED) {
+ if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
mContractedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
+ if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
mExpandedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
+ if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
mHeadsUpWrapper.setDark(dark, fade, delay);
}
- if (mSingleLineView != null && mVisibleType == VISIBLE_TYPE_SINGLELINE) {
+ if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
mSingleLineView.setDark(dark, fade, delay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 4e3ecb1..dba7130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -170,12 +170,13 @@
invalidate();
return;
}
- area.left = Math.max(area.left, 0);
- area.top = Math.max(area.top, 0);
- area.right = Math.min(area.right, getWidth());
- area.bottom = Math.min(area.bottom, getHeight());
- mExcludedRect.set(area);
- mHasExcludedArea = area.left < area.right && area.top < area.bottom;
+
+ int left = Math.max(area.left, 0);
+ int top = Math.max(area.top, 0);
+ int right = Math.min(area.right, getWidth());
+ int bottom = Math.min(area.bottom, getHeight());
+ mExcludedRect.set(left, top, right, bottom);
+ mHasExcludedArea = left < right && top < bottom;
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index c836637..0a7ee51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -21,6 +21,8 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
+
/**
* A common base class for all views in the notification stack scroller which don't have a
* background.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5a7cf86..e4accf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -24,15 +24,14 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.graphics.drawable.ScaleDrawable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index bed64a3..a58fa86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -25,11 +25,13 @@
import android.support.v4.util.SimpleArrayMap;
import android.view.View;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ActivityStarter;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -62,8 +64,8 @@
private SimpleArrayMap<String, Integer> mFacetPackageMap
= new SimpleArrayMap<String, Integer>();
- private List<Intent> mIntents = new ArrayList<Intent>();
- private List<Intent> mLongPressIntents = new ArrayList<Intent>();
+ private List<Intent> mIntents;
+ private List<Intent> mLongPressIntents;
private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
@@ -112,16 +114,19 @@
throw new RuntimeException("car_facet array lengths do not match");
}
+ mIntents = createEmptyIntentList(icons.length());
+ mLongPressIntents = createEmptyIntentList(icons.length());
+
for (int i = 0; i < icons.length(); i++) {
Drawable icon = icons.getDrawable(i);
try {
- mIntents.add(i,
+ mIntents.set(i,
Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
String longpressUri = longpressIntents.getString(i);
boolean hasLongpress = !longpressUri.isEmpty();
if (hasLongpress) {
- mLongPressIntents.add(i,
+ mLongPressIntents.set(i,
Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
}
@@ -299,4 +304,8 @@
setCurrentFacet(index);
startActivity(mLongPressIntents.get(index));
}
+
+ private List<Intent> createEmptyIntentList(int size) {
+ return Arrays.asList(new Intent[size]);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index efc3646..d530759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -17,20 +17,13 @@
package com.android.systemui.statusbar.car;
import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.R.color;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.NavigationBarView;
-import java.util.ArrayList;
-import java.util.HashMap;
-
/**
* A custom navigation bar for the automotive use case.
* <p>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 504f059..59e4244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -19,6 +19,7 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
+
import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 3025092..8e6c153 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.car;
-import android.content.Context;
-import android.provider.Settings;
import android.view.View;
import android.view.ViewStub;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index bf291d3..81483c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -30,6 +30,8 @@
private static Pools.SimplePool<HeaderTransformState> sInstancePool
= new Pools.SimplePool<>(40);
private View mExpandButton;
+ private View mWorkProfileIcon;
+ private TransformState mWorkProfileState;
@Override
public void initFrom(View view) {
@@ -37,13 +39,16 @@
if (view instanceof NotificationHeaderView) {
NotificationHeaderView header = (NotificationHeaderView) view;
mExpandButton = header.getExpandButton();
+ mWorkProfileState = TransformState.obtain();
+ mWorkProfileIcon = header.getWorkProfileIcon();
+ mWorkProfileState.initFrom(mWorkProfileIcon);
}
}
@Override
public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
// if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one.
+ // but the expand button, so lets fade just that one and transform the work profile icon.
if (!(mTransformedView instanceof NotificationHeaderView)) {
return false;
}
@@ -66,7 +71,7 @@
@Override
public void transformViewFrom(TransformState otherState) {
// if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one.
+ // but the expand button, so lets fade just that one and transform the work profile icon.
if (!(mTransformedView instanceof NotificationHeaderView)) {
return;
}
@@ -79,10 +84,14 @@
if (headerChild.getVisibility() == View.GONE) {
continue;
}
- if (headerChild != mExpandButton) {
- headerChild.setVisibility(View.VISIBLE);
- } else {
+ if (headerChild == mExpandButton) {
CrossFadeHelper.fadeIn(mExpandButton);
+ } else {
+ headerChild.setVisibility(View.VISIBLE);
+ if (headerChild == mWorkProfileIcon) {
+ mWorkProfileState.animateViewFrom(
+ ((HeaderTransformState) otherState).mWorkProfileState);
+ }
}
}
return;
@@ -99,6 +108,9 @@
@Override
public void recycle() {
super.recycle();
+ if (mWorkProfileState != null) {
+ mWorkProfileState.recycle();
+ }
sInstancePool.release(this);
}
@@ -106,6 +118,7 @@
protected void reset() {
super.reset();
mExpandButton = null;
+ mWorkProfileState = null;
}
public void setVisible(boolean visible) {
@@ -125,6 +138,10 @@
if (headerChild == mExpandButton) {
headerChild.setAlpha(visible ? 1.0f : 0.0f);
}
+ if (headerChild == mWorkProfileIcon) {
+ headerChild.setTranslationX(0);
+ headerChild.setTranslationY(0);
+ }
}
}
@@ -144,6 +161,10 @@
headerChild.animate().cancel();
headerChild.setVisibility(View.VISIBLE);
headerChild.setAlpha(1.0f);
+ if (headerChild == mWorkProfileIcon) {
+ headerChild.setTranslationX(0);
+ headerChild.setTranslationY(0);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index 5eed5ed..ec73935 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
@@ -32,8 +31,6 @@
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
-import java.util.ArrayList;
-
/**
* A hybrid view which may contain information about one ore more notifications.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index ce9540b..c561601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Bundle;
-import android.os.Parcelable;
import android.service.notification.StatusBarNotification;
import android.view.View;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 97bf4b4..60c1911 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -35,6 +35,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index f43a5d0..5a71caf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -28,22 +28,18 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
-import java.util.Collection;
import java.util.Stack;
/**
@@ -95,6 +91,7 @@
@Override
public void notifyContentUpdated(StatusBarNotification notification) {
+ super.notifyContentUpdated(notification);
// Reinspect the notification.
resolveHeaderViews();
updateInvertHelper();
@@ -150,6 +147,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 3475d13..b060245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -25,8 +25,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -172,6 +172,9 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
super.setDark(dark, fade, delay);
setPictureGrayscale(dark, fade, delay);
setProgressBarDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index c931800..7089b78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,12 +16,10 @@
package com.android.systemui.statusbar.notification;
-import android.view.View;
import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
/**
* A util class for various reusable functions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a1cf07e..f50b976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -31,6 +31,7 @@
public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
+ protected boolean mDark;
public static NotificationViewWrapper wrap(Context ctx, View v) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -56,13 +57,17 @@
* @param fade whether to animate the transition if the mode changes
* @param delay if fading, the delay of the animation
*/
- public abstract void setDark(boolean dark, boolean fade, long delay);
+ public void setDark(boolean dark, boolean fade, long delay) {
+ mDark = dark;
+ }
/**
* Notifies this wrapper that the content of the view might have changed.
* @param notification
*/
- public void notifyContentUpdated(StatusBarNotification notification) {};
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ mDark = false;
+ };
/**
* Update the appearance of the expand button.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 3e1c40a..5832d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -26,10 +26,10 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
@@ -286,6 +286,9 @@
}
public void setVisible(boolean visible) {
+ if (mTransformedView.getVisibility() == View.GONE) {
+ return;
+ }
mTransformedView.animate().cancel();
mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 37e5558..5796edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
@@ -29,10 +28,9 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
-import android.view.animation.LinearInterpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class BarTransitions {
private static final boolean DEBUG = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
index 497f044..9a94d34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
+
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index aea9e1e..30d24ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,12 +14,12 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
-
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index b5dba18..7d4515e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -25,9 +25,9 @@
import android.util.Log;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
-import com.android.systemui.statusbar.Interpolators;
/**
* Controller which handles all the doze animations of the scrims.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 7135836..1c9d937 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -190,7 +190,8 @@
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
break;
case MODE_WAKE_AND_UNLOCK_PULSING:
- mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */);
+ mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+ true /* allowEnterAnimation */);
// Fall through.
case MODE_WAKE_AND_UNLOCK:
mStatusBarWindowManager.setStatusBarFocusable(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index e7064e5..b5b7f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -21,7 +21,6 @@
import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index c220efe..915b565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -25,10 +25,10 @@
import android.view.View;
import android.view.ViewConfiguration;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 94d3829..83a15ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -45,8 +45,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -55,10 +53,10 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 347ba3d..b9e1ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -21,6 +21,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.widget.LockPatternUtils;
@@ -99,7 +100,20 @@
mRoot.setVisibility(View.VISIBLE);
mKeyguardView.onResume();
showPromptReason(mBouncerPromptReason);
- mKeyguardView.startAppearAnimation();
+ if (mKeyguardView.getHeight() != 0) {
+ mKeyguardView.startAppearAnimation();
+ } else {
+ mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
+ mKeyguardView.startAppearAnimation();
+ return true;
+ }
+ });
+ mKeyguardView.requestLayout();
+ }
mShowingSoon = false;
mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e67aa84..7fbb176 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -28,8 +28,8 @@
import android.widget.TextView;
import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 8717a15..03dd25e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -66,6 +66,9 @@
}
public boolean hasMultipleUsers() {
+ if (mUserListener == null) {
+ return false;
+ }
return mUserListener.getCount() != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 92288a3..a2586f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -27,13 +27,16 @@
import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.tuner.TunerService;
-import static android.view.WindowManager.*;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
/**
* Class to detect gestures on the navigation bar.
@@ -218,8 +221,7 @@
mDivider.getView().startDragging(false /* animate */, true /* touching*/);
}
mDockWindowTouchSlopExceeded = true;
- MetricsLogger.action(mContext,
- MetricsLogger.ACTION_WINDOW_DOCK_SWIPE);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 7395a33..9359301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -26,7 +27,9 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
+
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.tuner.TunerService;
import java.util.Objects;
@@ -37,20 +40,30 @@
public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
- private static final String MENU_IME = "menu_ime";
- private static final String BACK = "back";
- private static final String HOME = "home";
- private static final String RECENT = "recent";
- private static final String NAVSPACE = "space";
+ public static final String MENU_IME = "menu_ime";
+ public static final String BACK = "back";
+ public static final String HOME = "home";
+ public static final String RECENT = "recent";
+ public static final String NAVSPACE = "space";
+ public static final String CLIPBOARD = "clipboard";
+ public static final String KEY = "key";
public static final String GRAVITY_SEPARATOR = ";";
public static final String BUTTON_SEPARATOR = ",";
- private final LayoutInflater mLayoutInflater;
- private final LayoutInflater mLandscapeInflater;
+ public static final String SIZE_MOD_START = "[";
+ public static final String SIZE_MOD_END = "]";
- private FrameLayout mRot0;
- private FrameLayout mRot90;
+ public static final String KEY_CODE_START = "(";
+ public static final String KEY_IMAGE_DELIM = ":";
+ public static final String KEY_CODE_END = ")";
+
+ protected final LayoutInflater mLayoutInflater;
+ protected final LayoutInflater mLandscapeInflater;
+
+ protected FrameLayout mRot0;
+ protected FrameLayout mRot90;
+
private SparseArray<ButtonDispatcher> mButtonDispatchers;
private String mCurrentLayout;
@@ -72,7 +85,7 @@
inflateLayout(getDefaultLayout());
}
- private String getDefaultLayout() {
+ protected String getDefaultLayout() {
return mContext.getString(R.string.config_navBarLayout);
}
@@ -128,9 +141,9 @@
}
}
- private void inflateLayout(String newLayout) {
+ protected void inflateLayout(String newLayout) {
mCurrentLayout = newLayout;
- String[] sets = newLayout.split(GRAVITY_SEPARATOR);
+ String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
String[] start = sets[0].split(BUTTON_SEPARATOR);
String[] center = sets[1].split(BUTTON_SEPARATOR);
String[] end = sets[2].split(BUTTON_SEPARATOR);
@@ -165,6 +178,8 @@
}
private void copyToLightsout(View view, ViewGroup lightsOutParent) {
+ if (view == null) return;
+
if (view instanceof FrameLayout) {
// The only ViewGroup we support in here is a FrameLayout, so copy those manually.
FrameLayout original = (FrameLayout) view;
@@ -202,40 +217,88 @@
return new LayoutParams(layoutParams.width, layoutParams.height);
}
- private View inflateButton(String button, ViewGroup parent, boolean landscape) {
+ @Nullable
+ protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape) {
+ LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
+ float size = extractSize(buttonSpec);
+ String button = extractButton(buttonSpec);
View v = null;
if (HOME.equals(button)) {
- v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.home, parent, false);
+ v = inflater.inflate(R.layout.home, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (BACK.equals(button)) {
- v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.back, parent, false);
+ v = inflater.inflate(R.layout.back, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (RECENT.equals(button)) {
- v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.recent_apps, parent, false);
+ v = inflater.inflate(R.layout.recent_apps, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (MENU_IME.equals(button)) {
- v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.menu_ime, parent, false);
+ v = inflater.inflate(R.layout.menu_ime, parent, false);
} else if (NAVSPACE.equals(button)) {
- v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.nav_key_space, parent, false);
+ v = inflater.inflate(R.layout.nav_key_space, parent, false);
+ } else if (CLIPBOARD.equals(button)) {
+ v = inflater.inflate(R.layout.clipboard, parent, false);
+ } else if (button.startsWith(KEY)) {
+ String uri = extractImage(button);
+ int code = extractKeycode(button);
+ v = inflater.inflate(R.layout.custom_key, parent, false);
+ ((KeyButtonView) v).setCode(code);
+ if (uri != null) {
+ ((KeyButtonView) v).loadAsync(uri);
+ }
} else {
- throw new IllegalArgumentException("Unknown button " + button);
+ return null;
+ }
+
+ if (size != 0) {
+ ViewGroup.LayoutParams params = v.getLayoutParams();
+ params.width = (int) (params.width * size);
}
parent.addView(v);
addToDispatchers(v);
return v;
}
+ public static String extractImage(String buttonSpec) {
+ if (!buttonSpec.contains(KEY_IMAGE_DELIM)) {
+ return null;
+ }
+ final int start = buttonSpec.indexOf(KEY_IMAGE_DELIM);
+ String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_CODE_END));
+ return subStr;
+ }
+
+ public static int extractKeycode(String buttonSpec) {
+ if (!buttonSpec.contains(KEY_CODE_START)) {
+ return 1;
+ }
+ final int start = buttonSpec.indexOf(KEY_CODE_START);
+ String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_IMAGE_DELIM));
+ return Integer.parseInt(subStr);
+ }
+
+ public static float extractSize(String buttonSpec) {
+ if (!buttonSpec.contains(SIZE_MOD_START)) {
+ return 1;
+ }
+ final int sizeStart = buttonSpec.indexOf(SIZE_MOD_START);
+ String sizeStr = buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
+ return Float.parseFloat(sizeStr);
+ }
+
+ public static String extractButton(String buttonSpec) {
+ if (!buttonSpec.contains(SIZE_MOD_START)) {
+ return buttonSpec;
+ }
+ return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
+ }
+
private void addToDispatchers(View v) {
if (mButtonDispatchers != null) {
final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d86629f..5f5974e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,6 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.annotation.Nullable;
import android.app.ActivityManagerNative;
import android.app.StatusBarManager;
import android.content.Context;
@@ -47,6 +46,7 @@
import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 405ef05..03a597c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,6 +8,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
+
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8e89efd..277668f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -49,6 +49,7 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
@@ -57,7 +58,6 @@
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f036d04..c9bb15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -34,11 +34,11 @@
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6fa1f5df..2b961fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -26,6 +26,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -66,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
@@ -94,6 +96,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -104,6 +107,7 @@
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
@@ -113,8 +117,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
@@ -125,7 +127,6 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
@@ -243,6 +244,11 @@
* Prudently disable QS and notifications. */
private static final boolean ONLY_CORE_APPS;
+ /** If true, the lockscreen will show a distinct wallpaper */
+ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER =
+ !ActivityManager.isLowRamDeviceStatic()
+ && SystemProperties.getBoolean("debug.lockscreen_wallpaper", false);
+
/* If true, the device supports freeform window management.
* This affects the status bar UI. */
private static final boolean FREEFORM_WINDOW_MANAGEMENT;
@@ -460,7 +466,7 @@
if (state != null) {
if (!isPlaybackActive(state.getState())) {
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
}
}
@@ -470,7 +476,7 @@
super.onMetadataChanged(metadata);
if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
mMediaMetadata = metadata;
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
};
@@ -752,7 +758,7 @@
mDismissView.setOnButtonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
clearAllNotifications();
}
});
@@ -1122,8 +1128,7 @@
ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
initialBounds);
if (docked) {
- MetricsLogger.action(mContext,
- MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
return true;
}
}
@@ -1138,7 +1143,7 @@
if (shouldDisableNavbarGestures()) {
return false;
}
- MetricsLogger.action(mContext, MetricsLogger.ACTION_ASSIST_LONG_PRESS);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mAssistManager.startAssist(new Bundle() /* args */);
awakenDreams();
if (mNavigationBarView != null) {
@@ -1315,7 +1320,7 @@
}
if (key.equals(mMediaNotificationKey)) {
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
if (deferRemoval) {
mLatestRankingMap = ranking;
@@ -1373,6 +1378,9 @@
boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
boolean showingPublic = sensitive && isLockscreenPublicMode();
+ if (showingPublic) {
+ updatePublicContentView(ent, ent.notification);
+ }
ent.row.setSensitive(sensitive);
if (ent.autoRedacted && ent.legacy) {
// TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
@@ -1703,7 +1711,7 @@
if (metaDataChanged) {
updateNotifications();
}
- updateMediaMetaData(metaDataChanged);
+ updateMediaMetaData(metaDataChanged, true);
}
private int getMediaControllerPlaybackState(MediaController controller) {
@@ -1762,7 +1770,7 @@
/**
* Refresh or remove lockscreen artwork from media metadata.
*/
- public void updateMediaMetaData(boolean metaDataChanged) {
+ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
if (mBackdrop == null) return; // called too early
@@ -1787,6 +1795,12 @@
// might still be null
}
}
+ if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
+ // TODO: use real lockscreen wallpaper.
+ WallpaperManager wallpaperManager = mContext
+ .getSystemService(WallpaperManager.class);
+ artworkBitmap = wallpaperManager.getBitmap();
+ }
final boolean hasArtwork = artworkBitmap != null;
@@ -1796,7 +1810,12 @@
// time to show some art!
if (mBackdrop.getVisibility() != View.VISIBLE) {
mBackdrop.setVisibility(View.VISIBLE);
- mBackdrop.animate().alpha(1f);
+ if (allowEnterAnimation) {
+ mBackdrop.animate().alpha(1f);
+ } else {
+ mBackdrop.animate().cancel();
+ mBackdrop.setAlpha(1f);
+ }
metaDataChanged = true;
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
@@ -3020,6 +3039,10 @@
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
notifyNavigationBarScreenOn(true);
}
+ else if (ENABLE_LOCKSCREEN_WALLPAPER
+ && Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
+ updateMediaMetaData(true, true);
+ }
}
};
@@ -3041,7 +3064,7 @@
}
} else if (ACTION_FAKE_ARTWORK.equals(action)) {
if (DEBUG_MEDIA_FAKE_ARTWORK) {
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
}
}
@@ -3105,7 +3128,7 @@
resetUserSetupObserver();
setControllerUsers();
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, false);
}
private void setControllerUsers() {
@@ -3524,7 +3547,7 @@
runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
mScrimController.forceHideScrims(false /* hide */);
- updateMediaMetaData(true /* metaDataChanged */);
+ updateMediaMetaData(true /* metaDataChanged */, true);
}
public boolean isCollapsing() {
@@ -3559,7 +3582,7 @@
beforeFading.run();
}
mScrimController.forceHideScrims(true /* hide */);
- updateMediaMetaData(false);
+ updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
mNotificationPanel.animate()
.alpha(0)
@@ -3761,7 +3784,7 @@
updateStackScrollerState(goingToFullShade, fromShadeLocked);
updateNotifications();
checkBarModes();
- updateMediaMetaData(false);
+ updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
mStatusBarKeyguardViewManager.isSecure());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 37d61b9..df5a622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -34,6 +34,7 @@
import android.provider.Settings.Global;
import android.telecom.TelecomManager;
import android.util.Log;
+
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 9c2159be..8e2d828 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -28,6 +28,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.external.CustomTile;
@@ -51,6 +52,7 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DisplayController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -101,6 +103,7 @@
private final TileServices mServices;
private final List<Callback> mCallbacks = new ArrayList<>();
+ private final DisplayController mDisplayController;
private View mHeader;
public QSTileHost(Context context, PhoneStatusBar statusBar,
@@ -127,6 +130,7 @@
mSecurity = security;
mBattery = battery;
mIconController = iconController;
+ mDisplayController = new DisplayController(mContext);
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
Process.THREAD_PRIORITY_BACKGROUND);
@@ -277,6 +281,10 @@
return mIconController;
}
+ public DisplayController getDisplayController() {
+ return mDisplayController;
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index f18c341..9aeb1f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -31,6 +31,7 @@
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
+
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 7247b57..6220fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -28,7 +28,7 @@
import android.view.animation.AnimationUtils;
import com.android.keyguard.AlphaOptimizedImageButton;
-import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.Interpolators;
public class SettingsButton extends AlphaOptimizedImageButton {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index c6537e8..9996b75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -39,8 +39,8 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 382de19..fcaf050 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -24,7 +24,6 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager;
import com.android.keyguard.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 35a17e4..eb5b57e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -30,7 +30,6 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 116237d..0442ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.R;
-
import android.app.AlertDialog;
import android.content.Context;
import android.view.WindowManager;
+import com.android.systemui.R;
+
/**
* Base class for dialogs that should appear over panels and keyguard.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index 1aae496..d5a91bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -31,8 +31,8 @@
import android.graphics.drawable.Drawable;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class TrustDrawable extends Drawable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 4f33d82..093a827 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -16,23 +16,22 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.systemui.R;
+
/**
* A view that displays a user image cropped to a circle with a frame.
*/
@@ -174,6 +173,7 @@
float halfW = getWidth() / 2f;
float halfH = getHeight() / 2f;
float halfSW = Math.min(halfH, halfW);
+ updateDrawableIfDisabled();
if (mBitmap != null && mScale > 0) {
int saveCount = canvas.getSaveCount();
canvas.save();
@@ -249,22 +249,25 @@
return;
}
mIsDisabled = disabled;
+ invalidate();
+ }
+
+ private void updateDrawableIfDisabled() {
int disabledColor = getContext().getColor(R.color.qs_tile_disabled_color);
PorterDuffColorFilter filter = new PorterDuffColorFilter(disabledColor,
PorterDuff.Mode.SRC_ATOP);
if (mBitmap != null) {
- if (disabled) {
+ if (mIsDisabled) {
mBitmapPaint.setColorFilter(filter);
} else {
mBitmapPaint.setColorFilter(null);
}
} else if (mDrawable != null) {
- if (disabled) {
+ if (mIsDisabled) {
mDrawable.setColorFilter(filter);
} else {
mDrawable.setColorFilter(null);
}
}
- invalidate();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 8fa9c7e..e7e2ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -33,6 +33,7 @@
Collection<CachedBluetoothDevice> getDevices();
void connect(CachedBluetoothDevice device);
void disconnect(CachedBluetoothDevice device);
+ boolean canConfigBluetooth();
public interface Callback {
void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index a04edf7..6439bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,11 +16,14 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -39,6 +42,8 @@
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final LocalBluetoothManager mLocalBluetoothManager;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
@@ -54,6 +59,14 @@
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
}
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
+ }
+
+ @Override
+ public boolean canConfigBluetooth() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
+ UserHandle.of(mCurrentUser));
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 59d54ff..3bd68a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -20,8 +20,8 @@
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index e344954..b89a77b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
-
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -41,6 +39,8 @@
import java.util.Set;
import java.util.UUID;
+import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+
/** Platform implementation of the cast controller. **/
public class CastControllerImpl implements CastController {
private static final String TAG = "CastController";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 7054bb8..3293964 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import libcore.icu.LocaleData;
+
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -36,12 +38,12 @@
import android.view.Display;
import android.view.View;
import android.widget.TextView;
+
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import libcore.icu.LocaleData;
import java.text.SimpleDateFormat;
import java.util.Calendar;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
new file mode 100644
index 0000000..d47050c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import libcore.util.Objects;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
+
+import java.util.ArrayList;
+
+public class DisplayController implements TunerService.Tunable {
+
+ public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
+ public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+ public static final String COLOR_STATE = "sysui_color_matrix_state";
+
+ public static final int COLOR_STATE_DISABLED = 0;
+ public static final int COLOR_STATE_ENABLED = 1;
+ public static final int COLOR_STATE_AUTO = 2;
+
+ public static final String AUTO_STRING = "auto_mode";
+ public static final String NONE_STRING = "none";
+
+ public static final int AUTO_INDEX = 2;
+ public static final int CUSTOM_INDEX = 3;
+
+ // Night mode ~= 3400 K
+ private static final float[] NIGHT_VALUES = new float[] {
+ 1, 0, 0, 0,
+ 0, .754f, 0, 0,
+ 0, 0, .516f, 0,
+ 0, 0, 0, 1,
+ };
+ public static final float[] IDENTITY_MATRIX = new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+
+ private final ArrayList<Listener> mListeners = new ArrayList<>();
+
+ private final Context mContext;
+
+ private String mCurrentValue;
+ private boolean mListening;
+
+ public DisplayController(Context context) {
+ mContext = context;
+ TunerService.get(mContext).addTunable(this, COLOR_STATE,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ }
+
+ public void addListener(Listener listener) {
+ mListeners.add(listener);
+ listener.onCurrentMatrixChanged();
+ }
+
+ public void removeListener(Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ public boolean isEnabled() {
+ return TunerService.get(mContext).getValue(COLOR_STATE, COLOR_STATE_DISABLED)
+ != COLOR_STATE_DISABLED;
+ }
+
+ public boolean isAuto() {
+ return mListening;
+ }
+
+ public void setAuto(boolean auto) {
+ TunerService.get(mContext).setValue(COLOR_STATE, auto ? COLOR_STATE_AUTO
+ : COLOR_STATE_DISABLED);
+ }
+
+ public boolean isCustomSet() {
+ return isCustomEnabled() && Objects.equal(getCurrentMatrix(), getCustomValues());
+ }
+
+ public String getCurrentMatrix() {
+ return mCurrentValue;
+ }
+
+ public String getCustomValues() {
+ return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
+ }
+
+ public boolean isCustomEnabled() {
+ return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_ENABLED, 0) != 0;
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(key)) {
+ mCurrentValue = newValue;
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onCurrentMatrixChanged();
+ }
+ } else if (COLOR_STATE.equals(key)) {
+ final boolean listening = newValue != null
+ && Integer.parseInt(newValue) == COLOR_STATE_AUTO;
+ if (listening && !mListening) {
+ mListening = true;
+ mContext.registerReceiver(mReceiver,
+ new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+ updateNightMode();
+ } else if (!listening && mListening) {
+ mListening = false;
+ mContext.unregisterReceiver(mReceiver);
+ }
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onCurrentMatrixChanged();
+ }
+ }
+ }
+
+ private void updateNightMode() {
+ final int uiMode = mContext.getResources().getConfiguration().uiMode;
+ final boolean isNightMode = (uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ String value = null;
+ if (isNightMode) {
+ value = toString(NIGHT_VALUES);
+ }
+ TunerService.get(mContext).setValue(Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ value);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
+ updateNightMode();
+ }
+ }
+ };
+
+ public interface Listener {
+ void onCurrentMatrixChanged();
+ }
+
+ public static String[] getColorTransforms(Context context) {
+ return new String[] {
+ NONE_STRING,
+ toString(NIGHT_VALUES),
+ AUTO_STRING, // Blank spot for auto values
+ null, // Blank spot for custom values
+ };
+ }
+
+ public static CharSequence[] getColorTitles(Context context) {
+ // TODO: Move to string array resource.
+ return new CharSequence[]{
+ context.getString(R.string.color_matrix_none),
+ context.getString(R.string.color_matrix_night),
+ context.getString(R.string.color_matrix_auto),
+ context.getString(R.string.color_matrix_custom),
+ };
+ }
+
+ public static String toString(float[] values) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < values.length; i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(values[i]);
+ }
+ return builder.toString();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 7ca91a5..b036936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,6 +22,7 @@
boolean isHotspotEnabled();
boolean isHotspotSupported();
void setHotspotEnabled(boolean enabled);
+ boolean isTetheringAllowed();
public interface Callback {
void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5719f76..61d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.TetherUtil;
@@ -39,13 +42,17 @@
private final Receiver mReceiver = new Receiver();
private final ConnectivityManager mConnectivityManager;
private final Context mContext;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private int mHotspotState;
public HotspotControllerImpl(Context context) {
mContext = context;
- mConnectivityManager = (ConnectivityManager)context.getSystemService(
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,6 +102,12 @@
return TetherUtil.isTetheringSupported(mContext);
}
+ @Override
+ public boolean isTetheringAllowed() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
+ UserHandle.of(mCurrentUser));
+ }
+
static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index d739d6c1..57e092a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -31,8 +31,8 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import java.util.ArrayList;
import java.util.HashSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index ba284c9..c8c824a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -20,8 +20,11 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.hardware.input.InputManager;
import android.media.AudioManager;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -99,6 +102,24 @@
setBackground(new KeyButtonRipple(context, this));
}
+ public void setCode(int code) {
+ mCode = code;
+ }
+
+ public void loadAsync(String uri) {
+ new AsyncTask<String, Void, Drawable>() {
+ @Override
+ protected Drawable doInBackground(String... params) {
+ return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
+ }
+
+ @Override
+ protected void onPostExecute(Drawable drawable) {
+ setImageDrawable(drawable);
+ }
+ }.execute(uri);
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index cec0c0a..970fed0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.os.RemoteException;
import android.view.WindowManagerGlobal;
+
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.settings.CurrentUserTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 0959b0c..867a8a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,20 +21,18 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
-import android.graphics.Interpolator;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
-import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..401943e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,6 +21,7 @@
boolean setLocationEnabled(boolean enabled);
void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
+ boolean isUserLocationRestricted();
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 7517f97..436a40d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,6 +52,7 @@
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
+ private final int mCurrentUser;
private boolean mAreActiveLocationRequests;
@@ -73,6 +74,7 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -103,10 +105,6 @@
* @return true if attempt to change setting was successful.
*/
public boolean setLocationEnabled(boolean enabled) {
- int currentUserId = ActivityManager.getCurrentUser();
- if (isUserLocationRestricted(currentUserId)) {
- return false;
- }
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
@@ -115,7 +113,7 @@
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
}
/**
@@ -133,11 +131,10 @@
/**
* Returns true if the current user is restricted from using location.
*/
- private boolean isUserLocationRestricted(int userId) {
+ public boolean isUserLocationRestricted() {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- return um.hasUserRestriction(
- UserManager.DISALLOW_SHARE_LOCATION,
- new UserHandle(userId));
+ return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+ UserHandle.of(mCurrentUser));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index ad8e3bd..8fd4d9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -206,7 +206,8 @@
// Show icon in QS when we are connected or need to show roaming.
boolean showDataIcon = mCurrentState.dataConnected
- || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+ || mCurrentState.iconGroup == TelephonyIcons.ROAMING
+ || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
getCurrentIconId(), contentDescription);
@@ -227,7 +228,8 @@
&& !mCurrentState.carrierNetworkChangeMode
&& mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault
- || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+ || mCurrentState.iconGroup == TelephonyIcons.ROAMING
+ || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
int typeIcon = showDataIcon ? icons.mDataType : 0;
mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
@@ -385,6 +387,8 @@
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
} else if (isRoaming()) {
mCurrentState.iconGroup = TelephonyIcons.ROAMING;
+ } else if (isDataDisabled()) {
+ mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
if (isEmergencyOnly() != mCurrentState.isEmergency) {
mCurrentState.isEmergency = isEmergencyOnly();
@@ -399,6 +403,10 @@
notifyListenersIfNecessary();
}
+ private boolean isDataDisabled() {
+ return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
+ }
+
@VisibleForTesting
void setActivity(int activity) {
mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 755a5b3..93c7322 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.telephony.SubscriptionInfo;
+
import com.android.settingslib.net.DataUsageController;
import com.android.settingslib.wifi.AccessPoint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 107a904..eecf8c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -37,6 +37,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 61a9851..c6659d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -16,12 +16,6 @@
package com.android.systemui.statusbar.policy;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.RemoteInputController;
-
-import android.annotation.NonNull;
-import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
@@ -47,7 +41,9 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import java.util.ArrayList;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.RemoteInputController;
/**
* Host for the remote input.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6ddd7a3..a85fe0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -25,21 +25,17 @@
import android.net.IConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
import android.net.NetworkRequest;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
import com.android.systemui.R;
import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 5e9447e..c954d08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
-
import android.content.Context;
import android.text.format.DateFormat;
import android.util.Log;
@@ -24,6 +22,8 @@
import java.io.PrintWriter;
import java.util.BitSet;
+import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
+
/**
* Common base class for handling signal for both wifi and mobile data.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 83e0446..6ff8f77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -208,6 +208,8 @@
static final int ICON_CARRIER_NETWORK_CHANGE =
R.drawable.stat_sys_signal_carrier_network_change_animation;
+ static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
+
static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
@@ -215,6 +217,8 @@
static final int QS_ICON_CARRIER_NETWORK_CHANGE =
R.drawable.ic_qs_signal_carrier_network_change_animation;
+ static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
+
static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE,
@@ -373,5 +377,20 @@
false,
TelephonyIcons.QS_DATA_R
);
+
+ static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
+ "DataDisabled",
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ TelephonyIcons.TELEPHONY_NO_NETWORK,
+ TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.accessibility_cell_data_off,
+ TelephonyIcons.ICON_DATA_DISABLED,
+ false,
+ TelephonyIcons.QS_ICON_DATA_DISABLED
+ );
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 6931d1e..85ac755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -36,9 +36,9 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.util.UserIcons;
import com.android.systemui.BitmapHelper;
import com.android.systemui.R;
-import com.android.internal.util.UserIcons;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 05d9626..6ca7dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -22,9 +22,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -34,8 +32,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -44,12 +40,11 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
-import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.BitmapHelper;
@@ -622,7 +617,7 @@
private void checkIfAddUserDisallowed(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- UserManager.DISALLOW_ADD_USER, UserHandle.myUserId());
+ UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
if (admin != null) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
@@ -724,7 +719,7 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_USERDETAIL;
+ return MetricsEvent.QS_USERDETAIL;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index eab6e13..cc98eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -23,6 +23,7 @@
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.settingslib.wifi.WifiStatusTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index a3f571e..50e5b88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -19,7 +19,6 @@
import android.view.View;
import com.android.systemui.statusbar.ActivatableNotificationView;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index d5b57ac..d6276b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -46,6 +46,7 @@
import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.classifier.FalsingManager;
@@ -54,7 +55,6 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
@@ -1649,8 +1649,8 @@
bottom = Math.min(bottom, getHeight());
}
}
- mBackgroundBounds.top = top;
- mBackgroundBounds.bottom = bottom;
+ mBackgroundBounds.top = Math.max(0, top);
+ mBackgroundBounds.bottom = Math.min(getHeight(), bottom);
}
private ActivatableNotificationView getFirstPinnedHeadsUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index e75e8e8..cf4802d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -24,10 +24,10 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
index 41824ea..05fa27d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -16,10 +16,6 @@
package com.android.systemui.statusbar.stack;
-import android.view.View;
-
-import com.android.systemui.statusbar.ExpandableView;
-
/**
* A state of an expandable view
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
new file mode 100644
index 0000000..919f150
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.ClipboardManager.OnPrimaryClipChangedListener;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+public class ClipboardView extends ImageView implements OnPrimaryClipChangedListener {
+
+ private static final int TARGET_COLOR = 0x4dffffff;
+ private final ClipboardManager mClipboardManager;
+ private ClipData mCurrentClip;
+
+ public ClipboardView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mClipboardManager = context.getSystemService(ClipboardManager.class);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ startListening();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ stopListening();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN && mCurrentClip != null) {
+ startPocketDrag();
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_ENTERED:
+ setBackgroundDragTarget(true);
+ break;
+ case DragEvent.ACTION_DROP:
+ mClipboardManager.setPrimaryClip(event.getClipData());
+ case DragEvent.ACTION_DRAG_EXITED:
+ case DragEvent.ACTION_DRAG_ENDED:
+ setBackgroundDragTarget(false);
+ break;
+ }
+ return true;
+ }
+
+ private void setBackgroundDragTarget(boolean isTarget) {
+ setBackgroundColor(isTarget ? TARGET_COLOR : 0);
+ }
+
+ public void startPocketDrag() {
+ startDragAndDrop(mCurrentClip, new View.DragShadowBuilder(this), null,
+ View.DRAG_FLAG_GLOBAL);
+ }
+
+ public void startListening() {
+ mClipboardManager.addPrimaryClipChangedListener(this);
+ onPrimaryClipChanged();
+ }
+
+ public void stopListening() {
+ mClipboardManager.removePrimaryClipChangedListener(this);
+ }
+
+ @Override
+ public void onPrimaryClipChanged() {
+ mCurrentClip = mClipboardManager.getPrimaryClip();
+ setImageResource(mCurrentClip != null
+ ? R.drawable.clipboard_full : R.drawable.clipboard_empty);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
index 8ed1b06..dfacd03 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
@@ -19,6 +19,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -28,15 +29,15 @@
import android.support.v7.preference.DropDownPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.Switch;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DisplayController;
import java.util.Objects;
@@ -44,21 +45,6 @@
private static final String TAG = "ColorMatrixFragment";
- public static final int CUSTOM_INDEX = 2;
-
- // Night mode ~= 3400 K
- private static final float[] NIGHT_VALUES = new float[] {
- 1, 0, 0, 0,
- 0, .754f, 0, 0,
- 0, 0, .516f, 0,
- 0, 0, 0, 1,
- };
- public static final float[] IDENTITY_MATRIX = new float[]{
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
- };
private static final long RESET_DELAY = 10000;
private boolean mCustomEnabled;
@@ -67,20 +53,29 @@
private String mCustomValues;
private SwitchPreference mEnableCustomPreference;
private MatrixPreference mCustomPreference;
- private SwitchPreference mShowQs;
- private String mTiles;
+ private int mState;
+ private Switch mSwitch;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = getContext();
- TunerService.get(context).addTunable(this, ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED,
- ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, QSTileHost.TILES_SETTING,
+ TunerService.get(context).addTunable(this, DisplayController.COLOR_MATRIX_CUSTOM_ENABLED,
+ DisplayController.COLOR_MATRIX_CUSTOM_VALUES, DisplayController.COLOR_STATE,
Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
}
@Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = LayoutInflater.from(getContext()).inflate(
+ R.layout.color_matrix_settings, container, false);
+ ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
+ return view;
+ }
+
+ @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
final Context context = getPreferenceManager().getContext();
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
@@ -88,40 +83,33 @@
mSelectPreference = new DropDownPreference(context);
mSelectPreference.setTitle(R.string.color_transform);
mSelectPreference.setSummary("%s");
- mSelectPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ mSelectPreference.setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- int index = Integer.parseInt((String) newValue);
+ if (Objects.equals(newValue, DisplayController.AUTO_STRING)) {
+ Settings.Secure.putInt(context.getContentResolver(),
+ DisplayController.COLOR_STATE,
+ DisplayController.COLOR_STATE_AUTO);
+ return true;
+ }
+ if (Objects.equals(newValue, DisplayController.NONE_STRING)) {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ return true;
+ }
+ Settings.Secure.putInt(context.getContentResolver(),
+ DisplayController.COLOR_STATE,
+ DisplayController.COLOR_STATE_ENABLED);
+ final String value = (String) newValue;
Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, getValues()[index]);
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ value);
return true;
}
});
getPreferenceScreen().addPreference(mSelectPreference);
- mShowQs = new SwitchPreference(context);
- mShowQs.setTitle(R.string.color_matrix_show_qs);
- mShowQs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- boolean showTile = (Boolean) newValue;
- String newTiles;
- if (showTile) {
- newTiles = mTiles != null ? mTiles + "," + ColorMatrixTile.COLOR_MATRIX_SPEC
- : "default," + ColorMatrixTile.COLOR_MATRIX_SPEC;
- } else {
- newTiles =
- mTiles.replace(mTiles.contains(ColorMatrixTile.COLOR_MATRIX_SPEC+ ",")
- ? ColorMatrixTile.COLOR_MATRIX_SPEC + ","
- : "," + ColorMatrixTile.COLOR_MATRIX_SPEC, "");
- }
- Settings.Secure.putString(context.getContentResolver(), QSTileHost.TILES_SETTING,
- newTiles);
- return true;
- }
- });
- getPreferenceScreen().addPreference(mShowQs);
-
mEnableCustomPreference = new SwitchPreference(context);
mEnableCustomPreference.setTitle(R.string.color_enable_custom);
mEnableCustomPreference.setOnPreferenceChangeListener(
@@ -129,8 +117,12 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (Boolean) newValue;
+ if (!enabled && Objects.equals(mCurrentValue, mCustomValues)) {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ }
Settings.Secure.putInt(context.getContentResolver(),
- ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
+ DisplayController.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
return true;
}
});
@@ -141,6 +133,38 @@
}
@Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ View switchBar = view.findViewById(R.id.switch_bar);
+ mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+ mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+ switchBar.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int newState = mState != DisplayController.COLOR_STATE_DISABLED
+ ? DisplayController.COLOR_STATE_DISABLED
+ : DisplayController.COLOR_STATE_ENABLED;
+ ContentResolver contentResolver = getContext().getContentResolver();
+ if (newState == DisplayController.COLOR_STATE_DISABLED) {
+ String tiles = Settings.Secure.getString(contentResolver,
+ QSTileHost.TILES_SETTING);
+ if (tiles != null) {
+ if (tiles.contains(",colors")) {
+ tiles = tiles.replace(",colors", "");
+ } else if (tiles.contains("colors,")) {
+ tiles = tiles.replace("colors,", "");
+ }
+ Settings.Secure.putString(contentResolver, QSTileHost.TILES_SETTING,
+ tiles);
+ }
+ }
+ Settings.Secure.putInt(contentResolver,
+ DisplayController.COLOR_STATE, newState);
+ }
+ });
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
TunerService.get(getContext()).removeTunable(this);
@@ -148,20 +172,28 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+ if (DisplayController.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
mEnableCustomPreference.setChecked(mCustomEnabled);
- mCustomPreference.setEnabled(mCustomEnabled);
+ mCustomPreference.setEnabled(mCustomEnabled
+ && mState != DisplayController.COLOR_STATE_DISABLED);
updateSelectOptions();
- } else if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ } else if (DisplayController.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
mCustomValues = newValue;
+ if (mCustomValues == null) {
+ mCustomValues = DisplayController.toString(DisplayController.IDENTITY_MATRIX);
+ }
mCustomPreference.setValues(mCustomValues);
updateSelectOptions();
- } else if (QSTileHost.TILES_SETTING.equals(key)) {
- mTiles = newValue;
- boolean hasTile = newValue != null
- && newValue.contains(ColorMatrixTile.COLOR_MATRIX_SPEC);
- mShowQs.setChecked(hasTile);
+ } else if (DisplayController.COLOR_STATE.equals(key)) {
+ mState = newValue != null ? Integer.parseInt(newValue) : 0;
+ if (mSwitch != null) {
+ mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+ }
+ mSelectPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+ mEnableCustomPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+ mCustomPreference.setEnabled(mCustomEnabled
+ && mState != DisplayController.COLOR_STATE_DISABLED);
} else {
mCurrentValue = newValue;
updateSelectOptions();
@@ -169,41 +201,38 @@
}
private void updateSelectOptions() {
- final int N = CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
+ final int N = DisplayController.CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
String[] values = new String[N];
- CharSequence[] totalNames = getColorTitles(getContext());
CharSequence[] names = new CharSequence[N];
+ CharSequence[] totalNames = DisplayController.getColorTitles(getContext());
+ String[] entries = DisplayController.getColorTransforms(getContext());
+ entries[DisplayController.CUSTOM_INDEX] = mCustomValues != null ? mCustomValues : "";
for (int i = 0; i < N; i++) {
- values[i] = String.valueOf(i);
+ values[i] = entries[i];
names[i] = totalNames[i];
}
mSelectPreference.setEntries(names);
mSelectPreference.setEntryValues(values);
- String[] entries = getValues();
- for (int i = 0; i < values.length; i++) {
- if (Objects.equals(entries[i], mCurrentValue)) {
- mSelectPreference.setValueIndex(i);
- return;
- }
+ int index = 0;
+ if (mState == DisplayController.COLOR_STATE_AUTO) {
+ index = DisplayController.AUTO_INDEX;
+ } else if (mCustomValues != null && Objects.equals(mCurrentValue, mCustomValues)) {
+ index = DisplayController.CUSTOM_INDEX;
+ } else if (Objects.equals(mCurrentValue, entries[1])) {
+ index = 1;
}
- mSelectPreference.setSummary(R.string.color_matrix_unknown);
+ mSelectPreference.setValueIndex(index);
+ mSelectPreference.setSummary("%s");
return;
}
- private String[] getValues() {
- String[] ret = getColorTransforms();
- // Fill in custom based on tuner settings.
- ret[CUSTOM_INDEX] = mCustomValues;
- return ret;
- }
-
private void startRevertTimer() {
getView().postDelayed(mResetColorMatrix, RESET_DELAY);
}
private void onApply() {
Settings.Secure.putString(getContext().getContentResolver(),
- ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
+ DisplayController.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
getView().removeCallbacks(mResetColorMatrix);
}
@@ -212,35 +241,6 @@
mResetColorMatrix.run();
}
- public static String[] getColorTransforms() {
- return new String[] {
- null,
- toString(NIGHT_VALUES),
- null, // Blank spot for custom values
- null, // Unknown
- };
- }
-
- public static CharSequence[] getColorTitles(Context context) {
- return new CharSequence[] {
- context.getString(R.string.color_matrix_none),
- context.getString(R.string.color_matrix_night),
- context.getString(R.string.color_matrix_custom),
- context.getString(R.string.color_matrix_unknown),
- };
- }
-
- private static String toString(float[] values) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < values.length; i++) {
- if (builder.length() != 0) {
- builder.append(',');
- }
- builder.append(values[i]);
- }
- return builder.toString();
- }
-
private final Runnable mResetColorMatrix = new Runnable() {
@Override
public void run() {
@@ -259,14 +259,10 @@
}
public void setValues(String customValues) {
- if (customValues == null) {
- mValues = IDENTITY_MATRIX;
- } else {
- String[] strValues = customValues.split(",");
- mValues = new float[strValues.length];
- for (int i = 0; i < mValues.length; i++) {
- mValues[i] = Float.parseFloat(strValues[i]);
- }
+ String[] strValues = customValues.split(",");
+ mValues = new float[strValues.length];
+ for (int i = 0; i < mValues.length; i++) {
+ mValues[i] = Float.parseFloat(strValues[i]);
}
notifyChanged();
}
@@ -274,48 +270,38 @@
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- ViewGroup vg = (ViewGroup) holder.itemView.findViewById(R.id.edit_group);
- if (mValues == null) {
- return;
- }
- int childIndex = 0;
- for (int i = 0; i < mValues.length; i++) {
- final int index = i;
- while (!(vg.getChildAt(childIndex) instanceof EditText)) {
- childIndex++;
+ bindView(holder.findViewById(R.id.r_group), 0);
+ bindView(holder.findViewById(R.id.g_group), 5);
+ bindView(holder.findViewById(R.id.b_group), 10);
+ holder.findViewById(R.id.apply).setOnClickListener(this);
+ }
+
+ private void bindView(View view, final int index) {
+ SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+ seekBar.setMax(1000);
+ seekBar.setProgress((int) (1000 * mValues[index]));
+ seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mValues[index] = progress / 1000f;
}
- final EditText editText = (EditText) vg.getChildAt(childIndex++);
- editText.setText(String.valueOf(mValues[i]));
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void afterTextChanged(Editable s) {
- if (TextUtils.isEmpty(s.toString())) {
- return;
- }
- try {
- mValues[index] = Float.parseFloat(s.toString());
- } catch (NumberFormatException e) {
- mValues[index] = 0;
- }
- }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
- });
- }
- ((Button) holder.itemView.findViewById(R.id.apply)).setOnClickListener(this);
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
}
@Override
public void onClick(View v) {
+ startRevertTimer();
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- ColorMatrixFragment.toString(mValues));
+ DisplayController.toString(mValues));
RevertWarning.show(ColorMatrixFragment.this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
index 1fd2352..7b06393 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -17,18 +17,21 @@
import android.app.ActivityManager;
import android.provider.Settings;
-import com.android.internal.logging.MetricsLogger;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
-import libcore.util.Objects;
+import com.android.systemui.statusbar.policy.DisplayController;
-public class ColorMatrixTile extends QSTile<QSTile.State> implements TunerService.Tunable {
+import java.util.Objects;
- public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
- public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayController.Listener {
public static final String COLOR_MATRIX_SPEC = "colors";
+ private final DisplayController mDisplayController;
+
private int mIndex;
private String mCurrentValue;
@@ -38,18 +41,17 @@
public ColorMatrixTile(Host host) {
super(host);
+ mDisplayController = host.getDisplayController();
}
@Override
public void setListening(boolean listening) {
if (listening) {
- mValues = ColorMatrixFragment.getColorTransforms();
- mValueTitles = ColorMatrixFragment.getColorTitles(mContext);
- TunerService.get(mContext).addTunable(this, COLOR_MATRIX_CUSTOM_ENABLED,
- COLOR_MATRIX_CUSTOM_VALUES,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ mValues = DisplayController.getColorTransforms(mContext);
+ mValueTitles = DisplayController.getColorTitles(mContext);
+ mDisplayController.addListener(this);
} else {
- TunerService.get(mContext).removeTunable(this);
+ mDisplayController.removeListener(this);
}
}
@@ -61,47 +63,45 @@
@Override
protected void handleClick() {
mIndex++;
- if (!mCustomEnabled && (mIndex == ColorMatrixFragment.CUSTOM_INDEX)) {
- mIndex++;
- }
- if (mIndex == mValues.length - 1) {
- mIndex = 0;
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
- ActivityManager.getCurrentUser());
- refreshState();
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
- mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
- } else if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
- mValues[ColorMatrixFragment.CUSTOM_INDEX] = newValue;
+ if (mIndex == DisplayController.AUTO_INDEX) {
+ mDisplayController.setAuto(true);
} else {
- mCurrentValue = newValue;
- }
- // Last value is unknown, default to that.
- mIndex = mValues.length - 1;
- for (int i = 0; i < mValues.length - 1; i++) {
- if (Objects.equal(mCurrentValue, mValues[i])) {
- mIndex = i;
- break;
+ mDisplayController.setAuto(false);
+ if (!mDisplayController.isCustomEnabled()
+ && (mIndex == DisplayController.CUSTOM_INDEX)) {
+ mIndex++;
}
+ if (mIndex == mValues.length - 1) {
+ mIndex = 0;
+ }
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
+ ActivityManager.getCurrentUser());
}
refreshState();
}
@Override
protected void handleUpdateState(State state, Object arg) {
+ if (mDisplayController.isAuto()) {
+ mIndex = DisplayController.AUTO_INDEX;
+ } else if (mDisplayController.isCustomSet()) {
+ mIndex = DisplayController.CUSTOM_INDEX;
+ } else {
+ mIndex = Objects.equals(mDisplayController.getCurrentMatrix(), mValues[1]) ? 1 : 0;
+ }
state.icon = ResourceIcon.get(R.drawable.ic_colorize);
state.label = mValueTitles[mIndex];
state.contentDescription = mValueTitles[mIndex];
}
@Override
+ public void onCurrentMatrixChanged() {
+ refreshState();
+ }
+
+ @Override
public int getMetricsCategory() {
- return MetricsLogger.QS_COLOR_MATRIX;
+ return MetricsEvent.QS_COLOR_MATRIX;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index f1de234..f801963 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -31,6 +31,7 @@
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
@@ -94,13 +95,13 @@
@Override
public void onResume() {
super.onResume();
- MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, true);
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_DEMO_MODE, true);
}
@Override
public void onPause() {
super.onPause();
- MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, false);
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_DEMO_MODE, false);
}
@Override
@@ -131,10 +132,10 @@
mOnSwitch.setChecked(false);
stopDemoMode();
}
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ENABLED, enabled);
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ENABLED, enabled);
setGlobal(DemoMode.DEMO_MODE_ALLOWED, enabled ? 1 : 0);
} else if (preference == mOnSwitch) {
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ON, enabled);
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ON, enabled);
if (enabled) {
startDemoMode();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
new file mode 100644
index 0000000..096ecc0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.view.KeyEvent;
+
+import com.android.systemui.R;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+public class KeycodeSelectionHelper {
+
+ private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
+ private static final ArrayList<Integer> mKeycodes = new ArrayList<>();
+
+ private static final String KEYCODE_STRING = "KEYCODE_";
+
+ static {
+ Class<KeyEvent> cls = KeyEvent.class;
+ for (Field field : cls.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())
+ && field.getName().startsWith(KEYCODE_STRING)
+ && field.getType().equals(int.class)) {
+ try {
+ mKeycodeStrings.add(formatString(field.getName()));
+ mKeycodes.add((Integer) field.get(null));
+ } catch (IllegalAccessException e) {
+ }
+ }
+ }
+ }
+
+ // Force the string into something somewhat readable.
+ private static String formatString(String name) {
+ StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
+ .toLowerCase());
+ for (int i = 0; i < str.length(); i++) {
+ if (i == 0 || str.charAt(i - 1) == ' ') {
+ str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
+ }
+ }
+ return str.toString();
+ }
+
+ public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.select_keycode)
+ .setItems(mKeycodeStrings.toArray(new String[0]),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ listener.onSelectionComplete(mKeycodes.get(which));
+ }
+ }).show();
+ }
+
+ public static Intent getSelectImageIntent() {
+ return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
+ .setType("image/*");
+ }
+
+ public interface OnSelectionComplete {
+ void onSelectionComplete(int code);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
new file mode 100644
index 0000000..5ded885
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.CLIPBOARD;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.RECENT;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
+
+public class NavBarTuner extends Fragment implements TunerService.Tunable {
+
+ private static final int SAVE = Menu.FIRST + 1;
+ private static final int RESET = Menu.FIRST + 2;
+ private static final int READ_REQUEST = 42;
+
+ private static final float PREVIEW_SCALE = .95f;
+ private static final float PREVIEW_SCALE_LANDSCAPE = .75f;
+
+ private NavBarAdapter mNavBarAdapter;
+ private PreviewNavInflater mPreview;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.nav_bar_tuner, container, false);
+ inflatePreview((ViewGroup) view.findViewById(R.id.nav_preview_frame));
+ return view;
+ }
+
+ private void inflatePreview(ViewGroup view) {
+ Display display = getActivity().getWindowManager().getDefaultDisplay();
+ boolean isRotated = display.getRotation() == Surface.ROTATION_90
+ || display.getRotation() == Surface.ROTATION_270;
+
+ Configuration config = new Configuration(getContext().getResources().getConfiguration());
+ boolean isPhoneLandscape = isRotated && (config.smallestScreenWidthDp < 600);
+ final float scale = isPhoneLandscape ? PREVIEW_SCALE_LANDSCAPE : PREVIEW_SCALE;
+ config.densityDpi = (int) (config.densityDpi * scale);
+
+ mPreview = (PreviewNavInflater) LayoutInflater.from(getContext().createConfigurationContext(
+ config)).inflate(R.layout.nav_bar_tuner_inflater, view, false);
+ final ViewGroup.LayoutParams layoutParams = mPreview.getLayoutParams();
+ layoutParams.width = (int) ((isPhoneLandscape ? display.getHeight() : display.getWidth())
+ * scale);
+ // Not sure why, but the height dimen is not being scaled with the dp, set it manually
+ // for now.
+ layoutParams.height = (int) (layoutParams.height * scale);
+ if (isPhoneLandscape) {
+ int width = layoutParams.width;
+ layoutParams.width = layoutParams.height;
+ layoutParams.height = width;
+ }
+ view.addView(mPreview);
+
+ if (isRotated) {
+ mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
+ final View rot90 = mPreview.findViewById(R.id.rot90);
+ rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+ rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+ } else {
+ mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
+ final View rot0 = mPreview.findViewById(R.id.rot0);
+ rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+ rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+ }
+ }
+
+ private void notifyChanged() {
+ mPreview.onTuningChanged(NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ RecyclerView recyclerView = (RecyclerView) view.findViewById(android.R.id.list);
+ final Context context = getContext();
+ recyclerView.setLayoutManager(new LinearLayoutManager(context));
+ mNavBarAdapter = new NavBarAdapter(context);
+ recyclerView.setAdapter(mNavBarAdapter);
+ recyclerView.addItemDecoration(new Dividers(context));
+ final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mNavBarAdapter.mCallbacks);
+ mNavBarAdapter.setTouchHelper(itemTouchHelper);
+ itemTouchHelper.attachToRecyclerView(recyclerView);
+
+ TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String navLayout) {
+ if (!NAV_BAR_VIEWS.equals(key)) return;
+ Context context = getContext();
+ if (navLayout == null) {
+ navLayout = context.getString(R.string.config_navBarLayout);
+ }
+ String[] views = navLayout.split(GRAVITY_SEPARATOR);
+ String[] groups = new String[] { NavBarAdapter.START, NavBarAdapter.CENTER,
+ NavBarAdapter.END};
+ CharSequence[] groupLabels = new String[] { getString(R.string.start),
+ getString(R.string.center), getString(R.string.end) };
+ mNavBarAdapter.clear();
+ for (int i = 0; i < 3; i++) {
+ mNavBarAdapter.addButton(groups[i], groupLabels[i]);
+ for (String button : views[i].split(BUTTON_SEPARATOR)) {
+ mNavBarAdapter.addButton(button, getLabel(button, context));
+ }
+ }
+ mNavBarAdapter.addButton(NavBarAdapter.ADD, getString(R.string.add_button));
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ // TODO: Show save button conditionally, only when there are changes.
+ menu.add(Menu.NONE, SAVE, Menu.NONE, getString(R.string.save))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menu.add(Menu.NONE, RESET, Menu.NONE, getString(R.string.reset));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == SAVE) {
+ if (!mNavBarAdapter.hasHomeButton()) {
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.no_home_title)
+ .setMessage(R.string.no_home_message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ } else {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+ }
+ return true;
+ } else if (item.getItemId() == RESET) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ NAV_BAR_VIEWS, null);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private static CharSequence getLabel(String button, Context context) {
+ if (button.startsWith(HOME)) {
+ return context.getString(R.string.accessibility_home);
+ } else if (button.startsWith(BACK)) {
+ return context.getString(R.string.accessibility_back);
+ } else if (button.startsWith(RECENT)) {
+ return context.getString(R.string.accessibility_recent);
+ } else if (button.startsWith(NAVSPACE)) {
+ return context.getString(R.string.space);
+ } else if (button.startsWith(MENU_IME)) {
+ return context.getString(R.string.menu_ime);
+ } else if (button.startsWith(CLIPBOARD)) {
+ return context.getString(R.string.clipboard);
+ } else if (button.startsWith(KEY)) {
+ return context.getString(R.string.keycode);
+ }
+ return button;
+ }
+
+ private static class Holder extends RecyclerView.ViewHolder {
+ private TextView title;
+
+ public Holder(View itemView) {
+ super(itemView);
+ title = (TextView) itemView.findViewById(android.R.id.title);
+ }
+ }
+
+ private static class Dividers extends RecyclerView.ItemDecoration {
+ private final Drawable mDivider;
+
+ public Dividers(Context context) {
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.listDivider, value, true);
+ mDivider = context.getDrawable(value.resourceId);
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ final int left = parent.getPaddingLeft();
+ final int right = parent.getWidth() - parent.getPaddingRight();
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+ .getLayoutParams();
+ final int top = child.getBottom() + params.bottomMargin;
+ final int bottom = top + mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(c);
+ }
+ }
+ }
+
+ private void selectImage() {
+ startActivityForResult(KeycodeSelectionHelper.getSelectImageIntent(), READ_REQUEST);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == READ_REQUEST && resultCode == Activity.RESULT_OK && data != null) {
+ final Uri uri = data.getData();
+ final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ getContext().getContentResolver().takePersistableUriPermission(uri, takeFlags);
+ mNavBarAdapter.onImageSelected(uri);
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ private class NavBarAdapter extends RecyclerView.Adapter<Holder>
+ implements View.OnClickListener {
+
+ private static final String START = "start";
+ private static final String CENTER = "center";
+ private static final String END = "end";
+ private static final String ADD = "add";
+
+ private static final int ADD_ID = 0;
+ private static final int BUTTON_ID = 1;
+ private static final int CATEGORY_ID = 2;
+
+ private List<String> mButtons = new ArrayList<>();
+ private List<CharSequence> mLabels = new ArrayList<>();
+ private int mCategoryLayout;
+ private int mButtonLayout;
+ private ItemTouchHelper mTouchHelper;
+
+ // Stored keycode while we wait for image selection on a KEY.
+ private int mKeycode;
+
+ public NavBarAdapter(Context context) {
+ TypedArray attrs = context.getTheme().obtainStyledAttributes(null,
+ android.R.styleable.Preference, android.R.attr.preferenceStyle, 0);
+ mButtonLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+ attrs = context.getTheme().obtainStyledAttributes(null,
+ android.R.styleable.Preference, android.R.attr.preferenceCategoryStyle, 0);
+ mCategoryLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+ }
+
+ public void setTouchHelper(ItemTouchHelper itemTouchHelper) {
+ mTouchHelper = itemTouchHelper;
+ }
+
+ public void clear() {
+ mButtons.clear();
+ mLabels.clear();
+ notifyDataSetChanged();
+ }
+
+ public void addButton(String button, CharSequence label) {
+ mButtons.add(button);
+ mLabels.add(label);
+ notifyItemInserted(mLabels.size() - 1);
+ notifyChanged();
+ }
+
+ public boolean hasHomeButton() {
+ final int N = mButtons.size();
+ for (int i = 0; i < N; i++) {
+ if (mButtons.get(i).startsWith(HOME)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getNavString() {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 1; i < mButtons.size() - 1; i++) {
+ String button = mButtons.get(i);
+ if (button.equals(CENTER) || button.equals(END)) {
+ if (builder.length() == 0 || builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+ // No start or center buttons, fill with a space.
+ builder.append(NAVSPACE);
+ }
+ builder.append(GRAVITY_SEPARATOR);
+ continue;
+ } else if (builder.length() != 0 && !builder.toString().endsWith(
+ GRAVITY_SEPARATOR)) {
+ builder.append(BUTTON_SEPARATOR);
+ }
+ builder.append(button);
+ }
+ if (builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+ // No end buttons, fill with space.
+ builder.append(NAVSPACE);
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ String button = mButtons.get(position);
+ if (button.equals(START) || button.equals(CENTER) || button.equals(END)) {
+ return CATEGORY_ID;
+ }
+ if (button.equals(ADD)) {
+ return ADD_ID;
+ }
+ return BUTTON_ID;
+ }
+
+ @Override
+ public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final Context context = parent.getContext();
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final View view = inflater.inflate(getLayoutId(viewType), parent, false);
+ if (viewType == BUTTON_ID) {
+ inflater.inflate(R.layout.nav_control_widget,
+ (ViewGroup) view.findViewById(android.R.id.widget_frame));
+ }
+ return new Holder(view);
+ }
+
+ private int getLayoutId(int viewType) {
+ if (viewType == CATEGORY_ID) {
+ return mCategoryLayout;
+ }
+ return mButtonLayout;
+ }
+
+ @Override
+ public void onBindViewHolder(Holder holder, int position) {
+ holder.title.setText(mLabels.get(position));
+ if (holder.getItemViewType() == BUTTON_ID) {
+ bindButton(holder, position);
+ } else if (holder.getItemViewType() == ADD_ID) {
+ bindAdd(holder);
+ }
+ }
+
+ private void bindAdd(Holder holder) {
+ TypedValue value = new TypedValue();
+ final Context context = holder.itemView.getContext();
+ context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+ final ImageView icon = (ImageView) holder.itemView.findViewById(android.R.id.icon);
+ icon.setImageResource(R.drawable.ic_add);
+ icon.setImageTintList(ColorStateList.valueOf(context.getColor(value.resourceId)));
+ holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+ holder.itemView.setClickable(true);
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showAddDialog(v.getContext());
+ }
+ });
+ }
+
+ private void bindButton(final Holder holder, int position) {
+ holder.itemView.findViewById(android.R.id.icon_frame).setVisibility(View.GONE);
+ holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+ bindClick(holder.itemView.findViewById(R.id.close), holder);
+ bindClick(holder.itemView.findViewById(R.id.width), holder);
+ holder.itemView.findViewById(R.id.drag).setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ mTouchHelper.startDrag(holder);
+ return true;
+ }
+ });
+ }
+
+ private void showAddDialog(final Context context) {
+ final String[] options = new String[] {
+ BACK, HOME, RECENT, MENU_IME, NAVSPACE, CLIPBOARD, KEY,
+ };
+ final CharSequence[] labels = new CharSequence[options.length];
+ for (int i = 0; i < options.length; i++) {
+ labels[i] = getLabel(options[i], context);
+ }
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.select_button)
+ .setItems(labels, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (KEY.equals(options[which])) {
+ showKeyDialogs(context);
+ } else {
+ int index = mButtons.size() - 1;
+ showAddedMessage(context, options[which]);
+ mButtons.add(index, options[which]);
+ mLabels.add(index, labels[which]);
+
+ notifyItemInserted(index);
+ notifyChanged();
+ }
+ }
+ }).setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ private void onImageSelected(Uri uri) {
+ int index = mButtons.size() - 1;
+ mButtons.add(index, KEY + KEY_CODE_START + mKeycode + KEY_IMAGE_DELIM + uri.toString()
+ + KEY_CODE_END);
+ mLabels.add(index, getLabel(KEY, getContext()));
+
+ notifyItemInserted(index);
+ notifyChanged();
+ }
+
+ private void showKeyDialogs(final Context context) {
+ final KeycodeSelectionHelper.OnSelectionComplete listener =
+ new KeycodeSelectionHelper.OnSelectionComplete() {
+ @Override
+ public void onSelectionComplete(int code) {
+ mKeycode = code;
+ selectImage();
+ }
+ };
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.keycode)
+ .setMessage(R.string.keycode_description)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ KeycodeSelectionHelper.showKeycodeSelect(context, listener);
+ }
+ }).show();
+ }
+
+ private void showAddedMessage(Context context, String button) {
+ if (CLIPBOARD.equals(button)) {
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.clipboard)
+ .setMessage(R.string.clipboard_description)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+ }
+
+ private void bindClick(View view, Holder holder) {
+ view.setOnClickListener(this);
+ view.setTag(holder);
+ }
+
+ @Override
+ public void onClick(View v) {
+ Holder holder = (Holder) v.getTag();
+ if (v.getId() == R.id.width) {
+ showWidthDialog(holder, v.getContext());
+ } else if (v.getId() == R.id.close) {
+ int position = holder.getAdapterPosition();
+ mButtons.remove(position);
+ mLabels.remove(position);
+ notifyItemRemoved(position);
+ notifyChanged();
+ }
+ }
+
+ private void showWidthDialog(final Holder holder, Context context) {
+ final String buttonSpec = mButtons.get(holder.getAdapterPosition());
+ float amount = extractSize(buttonSpec);
+ final AlertDialog dialog = new AlertDialog.Builder(context)
+ .setTitle(R.string.adjust_button_width)
+ .setView(R.layout.nav_width_view)
+ .setNegativeButton(android.R.string.cancel, null).create();
+ dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ context.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface d, int which) {
+ final String button = extractButton(buttonSpec);
+ SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+ if (seekBar.getProgress() == 75) {
+ mButtons.set(holder.getAdapterPosition(), button);
+ } else {
+ float amount = (seekBar.getProgress() + 25) / 100f;
+ mButtons.set(holder.getAdapterPosition(), button
+ + SIZE_MOD_START + amount + SIZE_MOD_END);
+ }
+ notifyChanged();
+ }
+ });
+ dialog.show();
+ SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+ // Range is .25 - 1.75.
+ seekBar.setMax(150);
+ seekBar.setProgress((int) ((amount - .25f) * 100));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mButtons.size();
+ }
+
+ private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
+ @Override
+ public boolean isLongPressDragEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isItemViewSwipeEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getMovementFlags(RecyclerView recyclerView,
+ RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder.getItemViewType() != BUTTON_ID) {
+ return makeMovementFlags(0, 0);
+ }
+ int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+ return makeMovementFlags(dragFlags, 0);
+ }
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+ RecyclerView.ViewHolder target) {
+ int from = viewHolder.getAdapterPosition();
+ int to = target.getAdapterPosition();
+ if (to == 0) {
+ // Can't go above the top.
+ return false;
+ }
+ move(from, to, mButtons);
+ move(from, to, mLabels);
+ notifyChanged();
+ notifyItemMoved(from, to);
+ return true;
+ }
+
+ private <T> void move(int from, int to, List<T> list) {
+ list.add(from > to ? to : to + 1, list.get(from));
+ list.remove(from > to ? from + 1 : from);
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+ // Don't care.
+ }
+ };
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
new file mode 100644
index 0000000..e6e8f4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
+
+public class PreviewNavInflater extends NavigationBarInflaterView {
+
+ public PreviewNavInflater(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ // Immediately remove tuner listening, since this is a preview, all values will be injected
+ // manually.
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // Only a preview, not interactable.
+ return true;
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (NAV_BAR_VIEWS.equals(key)) {
+ // Since this is a preview we might get a bunch of random stuff, validate before sending
+ // for inflation.
+ if (isValidLayout(newValue)) {
+ super.onTuningChanged(key, newValue);
+ }
+ } else {
+ super.onTuningChanged(key, newValue);
+ }
+ }
+
+ private boolean isValidLayout(String newValue) {
+ if (newValue == null) {
+ return true;
+ }
+ int separatorCount = 0;
+ int lastGravitySeparator = 0;
+ for (int i = 0; i < newValue.length(); i++) {
+ if (newValue.charAt(i) == GRAVITY_SEPARATOR.charAt(0)) {
+ if (i == 0 || (i - lastGravitySeparator) == 1) {
+ return false;
+ }
+ lastGravitySeparator = i;
+ separatorCount++;
+ }
+ }
+ return separatorCount == 2 && (newValue.length() - lastGravitySeparator) != 1;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index 920ec75..f2f0382 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -24,6 +24,7 @@
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -63,14 +64,14 @@
if (!value) {
// If not enabled add to blacklist.
if (!mBlacklist.contains(getKey())) {
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_DISABLE,
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_DISABLE,
getKey());
mBlacklist.add(getKey());
setList(mBlacklist);
}
} else {
if (mBlacklist.remove(getKey())) {
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_ENABLE, getKey());
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_ENABLE, getKey());
setList(mBlacklist);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 4173ecc..4225b48 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -30,11 +30,15 @@
PreferenceFragment.OnPreferenceStartFragmentCallback,
PreferenceFragment.OnPreferenceStartScreenCallback {
+ private static final String TAG_TUNER = "tuner";
+
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment())
- .commit();
+ if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
+ getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+ TAG_TUNER).commit();
+ }
}
@Override
@@ -43,6 +47,7 @@
Class<?> cls = Class.forName(pref.getFragment());
Fragment fragment = (Fragment) cls.newInstance();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ setTitle(pref.getTitle());
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack("PreferenceFragment");
transaction.commit();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index a3fe6bb..9df5368 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -18,7 +18,6 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
-import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.database.ContentObserver;
import android.net.Uri;
@@ -30,12 +29,12 @@
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
@@ -60,11 +59,16 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
setHasOptionsMenu(true);
}
@Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
+ }
+
+ @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.tuner_prefs);
@@ -80,11 +84,12 @@
@Override
public void onResume() {
super.onResume();
+ getActivity().setTitle(R.string.system_ui_tuner);
updateBatteryPct();
getContext().getContentResolver().registerContentObserver(
System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
- MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true);
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, true);
}
@Override
@@ -92,7 +97,7 @@
super.onPause();
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
- MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, false);
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, false);
}
@Override
@@ -141,7 +146,7 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean v = (Boolean) newValue;
- MetricsLogger.action(getContext(), MetricsLogger.TUNER_BATTERY_PERCENTAGE, v);
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 47a4667..f298e16 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -33,6 +33,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
@@ -76,6 +77,22 @@
mUserTracker.startTracking();
}
+ public String getValue(String setting) {
+ return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
+ }
+
+ public void setValue(String setting, String value) {
+ Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
+ }
+
+ public int getValue(String setting, int def) {
+ return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
+ }
+
+ public void setValue(String setting, int value) {
+ Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
+ }
+
public void addTunable(Tunable tunable, String... keys) {
for (String key : keys) {
addTunable(tunable, key);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index e947ed5..f4a8873 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.tv.pip;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
@@ -37,8 +38,6 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import android.app.ActivityManager.RunningTaskInfo;
-
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 97c70ed..15c55f5 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.media.session.MediaController;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index de997a8..bc59a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
-import android.util.Log;
import android.view.View;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index 0979ffd..bafd1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -22,12 +22,9 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.UserInfo;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 893c939..8e0f9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -23,6 +23,7 @@
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.volume.VolumeDialogController.State;
import java.util.Arrays;
@@ -111,33 +112,33 @@
sb.append(" ");
switch (tag) {
case EVENT_SHOW_DIALOG:
- MetricsLogger.visible(context, MetricsLogger.VOLUME_DIALOG);
+ MetricsLogger.visible(context, MetricsEvent.VOLUME_DIALOG);
MetricsLogger.histogram(context, "volume_from_keyguard",
(Boolean) list[1] ? 1 : 0);
sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
break;
case EVENT_EXPAND:
- MetricsLogger.visibility(context, MetricsLogger.VOLUME_DIALOG_DETAILS,
+ MetricsLogger.visibility(context, MetricsEvent.VOLUME_DIALOG_DETAILS,
(Boolean) list[0]);
sb.append(list[0]);
break;
case EVENT_DISMISS_DIALOG:
- MetricsLogger.hidden(context, MetricsLogger.VOLUME_DIALOG);
+ MetricsLogger.hidden(context, MetricsEvent.VOLUME_DIALOG);
sb.append(DISMISS_REASONS[(Integer) list[0]]);
break;
case EVENT_ACTIVE_STREAM_CHANGED:
- MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_STREAM,
+ MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_STREAM,
(Integer) list[0]);
sb.append(AudioSystem.streamToString((Integer) list[0]));
break;
case EVENT_ICON_CLICK:
- MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_ICON,
+ MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_ICON,
(Integer) list[1]);
sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
.append(iconStateToString((Integer) list[1]));
break;
case EVENT_TOUCH_LEVEL_DONE:
- MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_SLIDER,
+ MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_SLIDER,
(Integer) list[1]);
// fall through
case EVENT_TOUCH_LEVEL_CHANGED:
@@ -147,13 +148,13 @@
.append(list[1]);
break;
case EVENT_KEY:
- MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_KEY,
+ MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_KEY,
(Integer) list[1]);
sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
.append(list[1]);
break;
case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
- MetricsLogger.action(context, MetricsLogger.ACTION_RINGER_MODE,
+ MetricsLogger.action(context, MetricsEvent.ACTION_RINGER_MODE,
(Integer) list[0]);
// fall through
case EVENT_INTERNAL_RINGER_MODE_CHANGED:
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index b005a2b..6aae9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -16,9 +16,6 @@
package com.android.systemui.volume;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
import android.animation.ValueAnimator;
@@ -77,6 +74,9 @@
import java.util.ArrayList;
import java.util.List;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
/**
* Visual presentation of the volume dialog.
*
@@ -254,7 +254,7 @@
if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
int w = dm.widthPixels;
final int max = mContext.getResources()
- .getDimensionPixelSize(R.dimen.standard_notification_panel_width);
+ .getDimensionPixelSize(R.dimen.volume_dialog_panel_width);
if (w > max) {
w = max;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 673a30b..99c0f59 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -41,7 +41,6 @@
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.Condition;
-import android.service.notification.ZenModeConfig;
import android.util.Log;
import android.util.SparseArray;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index f73ba6f..e9594a3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -51,6 +51,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -620,7 +621,7 @@
if (childTag == null || childTag == tag) continue;
childTag.rb.setChecked(false);
}
- MetricsLogger.action(mContext, MetricsLogger.QS_DND_CONDITION_SELECT);
+ MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
select(tag.condition);
announceConditionSelection(tag);
}
@@ -725,7 +726,7 @@
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
- MetricsLogger.action(mContext, MetricsLogger.QS_DND_TIME, up);
+ MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
@@ -928,7 +929,7 @@
if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
final int zen = (Integer) value;
if (fromClick) {
- MetricsLogger.action(mContext, MetricsLogger.QS_DND_ZEN_SELECT, zen);
+ MetricsLogger.action(mContext, MetricsEvent.QS_DND_ZEN_SELECT, zen);
}
if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
final Uri realConditionId = getRealConditionId(mSessionExitCondition);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index b7a41e2..964688b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,12 +17,15 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_JACK_FLAGS := --multi-dex native
+
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview
+ --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
+ --extra-packages android.support.v17.leanback
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
@@ -35,6 +38,7 @@
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res \
frameworks/base/packages/SystemUI/res \
frameworks/base/packages/Keyguard/res
@@ -48,7 +52,8 @@
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference
+ android-support-v14-preference \
+ android-support-v17-leanback
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index a71ba636..8c78a3a 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -55,12 +55,16 @@
**/
public class Allocation extends BaseObj {
+ private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16;
+
Type mType;
Bitmap mBitmap;
int mUsage;
Allocation mAdaptedAllocation;
int mSize;
+ MipmapControl mMipmapControl;
+ long mTimeStamp = -1;
boolean mReadAllowed = true;
boolean mWriteAllowed = true;
boolean mAutoPadding = false;
@@ -278,6 +282,17 @@
}
/**
+ * @hide
+ * Get the Mipmap control flag of the Allocation.
+ *
+ * @return the Mipmap control flag of the Allocation
+ *
+ */
+ public MipmapControl getMipmap() {
+ return mMipmapControl;
+ }
+
+ /**
* Enable/Disable AutoPadding for Vec3 elements.
* By default: Diabled.
*
@@ -359,6 +374,11 @@
}
}
+ Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
+ this(id, rs, t, usage);
+ mMipmapControl = mips;
+ }
+
protected void finalize() throws Throwable {
RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
super.finalize();
@@ -521,7 +541,7 @@
"Can only receive if IO_INPUT usage specified.");
}
mRS.validate();
- mRS.nAllocationIoReceive(getID(mRS));
+ mTimeStamp = mRS.nAllocationIoReceive(getID(mRS));
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1890,7 +1910,7 @@
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
- return new Allocation(id, rs, type, usage);
+ return new Allocation(id, rs, type, usage, mips);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1948,7 +1968,7 @@
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
- return new Allocation(id, rs, t, usage);
+ return new Allocation(id, rs, t, usage, MipmapControl.MIPMAP_NONE);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -2037,7 +2057,7 @@
}
// keep a reference to the Bitmap around to prevent GC
- Allocation alloc = new Allocation(id, rs, t, usage);
+ Allocation alloc = new Allocation(id, rs, t, usage, mips);
alloc.setBitmap(b);
return alloc;
}
@@ -2047,14 +2067,13 @@
if (id == 0) {
throw new RSRuntimeException("Load failed.");
}
- return new Allocation(id, rs, t, usage);
+ return new Allocation(id, rs, t, usage, mips);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
}
/**
- * @hide
* Gets or creates a ByteBuffer that contains the raw data of the current Allocation.
* If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer
* would contain the up-to-date data as READ ONLY.
@@ -2089,7 +2108,107 @@
}
/**
- * @hide
+ * Creates a new Allocation Array with the given {@link
+ * android.renderscript.Type}, and usage flags.
+ * Note: If the input allocation is of usage: USAGE_IO_INPUT,
+ * the created Allocation will be sharing the same BufferQueue.
+ *
+ * @param rs RenderScript context
+ * @param t RenderScript type describing data layout
+ * @param usage bit field specifying how the Allocation is
+ * utilized
+ * @param numAlloc Number of Allocations in the array.
+ * @return Allocation[]
+ */
+ public static Allocation[] createAllocations(RenderScript rs, Type t, int usage, int numAlloc) {
+ try {
+ Trace.traceBegin(RenderScript.TRACE_TAG, "createAllocations");
+ rs.validate();
+ if (t.getID(rs) == 0) {
+ throw new RSInvalidStateException("Bad Type");
+ }
+
+ Allocation[] mAllocationArray = new Allocation[numAlloc];
+ mAllocationArray[0] = createTyped(rs, t, usage);
+ if ((usage & USAGE_IO_INPUT) != 0) {
+ if (numAlloc > MAX_NUMBER_IO_INPUT_ALLOC) {
+ throw new RSIllegalArgumentException("Exceeds the max number of Allocations allowed: " +
+ MAX_NUMBER_IO_INPUT_ALLOC);
+ }
+ mAllocationArray[0].setupBufferQueue(numAlloc);;
+ }
+
+ for (int i=1; i<numAlloc; i++) {
+ mAllocationArray[i] = createFromAllcation(rs, mAllocationArray[0]);
+ }
+ return mAllocationArray;
+ } finally {
+ Trace.traceEnd(RenderScript.TRACE_TAG);
+ }
+ }
+
+ /**
+ * Creates a new Allocation with the given {@link
+ * android.renderscript.Allocation}. The same data layout of
+ * the input Allocation will be applied.
+ * If the input allocation is of usage: USAGE_IO_INPUT, the created
+ * Allocation will be sharing the same BufferQueue.
+ *
+ * @param rs Context to which the allocation will belong.
+ * @param alloc RenderScript Allocation describing data layout.
+ * @return Allocation sharing the same data structure.
+ */
+ static Allocation createFromAllcation(RenderScript rs, Allocation alloc) {
+ try {
+ Trace.traceBegin(RenderScript.TRACE_TAG, "createFromAllcation");
+ rs.validate();
+ if (alloc.getID(rs) == 0) {
+ throw new RSInvalidStateException("Bad input Allocation");
+ }
+
+ Type type = alloc.getType();
+ int usage = alloc.getUsage();
+ MipmapControl mips = alloc.getMipmap();
+ long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
+ if (id == 0) {
+ throw new RSRuntimeException("Allocation creation failed.");
+ }
+ Allocation outAlloc = new Allocation(id, rs, type, usage, mips);
+ if ((usage & USAGE_IO_INPUT) != 0) {
+ outAlloc.shareBufferQueue(alloc);
+ }
+ return outAlloc;
+ } finally {
+ Trace.traceEnd(RenderScript.TRACE_TAG);
+ }
+ }
+
+ /**
+ * Initialize BufferQueue with specified max number of buffers.
+ */
+ void setupBufferQueue(int numAlloc) {
+ mRS.validate();
+ if ((mUsage & USAGE_IO_INPUT) == 0) {
+ throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT.");
+ }
+ mRS.nAllocationSetupBufferQueue(getID(mRS), numAlloc);
+ }
+
+ /**
+ * Share the BufferQueue with another {@link #USAGE_IO_INPUT} Allocation.
+ *
+ * @param alloc Allocation to associate with allocation
+ */
+ void shareBufferQueue(Allocation alloc) {
+ mRS.validate();
+ if ((mUsage & USAGE_IO_INPUT) == 0) {
+ throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT.");
+ }
+ mGetSurfaceSurface = alloc.getSurface();
+ mRS.nAllocationShareBufferQueue(getID(mRS), alloc.getID(mRS));
+ }
+
+ /**
* Gets the stride of the Allocation.
* For a 2D or 3D Allocation, the raw data maybe padded so that each row of
* the Allocation has certain alignment. The size of each row including such
@@ -2107,6 +2226,26 @@
}
/**
+ * Get the timestamp for the most recent buffer held by this Allocation.
+ * The timestamp is guaranteed to be unique and monotonically increasing.
+ * Default value: -1. The timestamp will be updated after each {@link
+ * #ioReceive ioReceive()} call.
+ *
+ * It can be used to identify the images by comparing the unique timestamps
+ * when used with {@link android.hardware.camera2} APIs.
+ * Example steps:
+ * 1. Save {@link android.hardware.camera2.TotalCaptureResult} when the
+ * capture is completed.
+ * 2. Get the timestamp after {@link #ioReceive ioReceive()} call.
+ * 3. Comparing totalCaptureResult.get(CaptureResult.SENSOR_TIMESTAMP) with
+ * alloc.getTimeStamp().
+ * @return long Timestamp associated with the buffer held by the Allocation.
+ */
+ public long getTimeStamp() {
+ return mTimeStamp;
+ }
+
+ /**
* Returns the handle to a raw buffer that is being managed by the screen
* compositor. This operation is only valid for Allocations with {@link
* #USAGE_IO_INPUT}.
@@ -2210,7 +2349,7 @@
if(id == 0) {
throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
}
- return new Allocation(id, rs, t, usage);
+ return new Allocation(id, rs, t, usage, mips);
}
/**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 4788223..51fc7dd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -484,7 +484,6 @@
rsnAllocationCopyToBitmap(mContext, alloc, bmp);
}
-
native void rsnAllocationSyncAll(long con, long alloc, int src);
synchronized void nAllocationSyncAll(long alloc, int src) {
validate();
@@ -497,6 +496,16 @@
return rsnAllocationGetByteBuffer(mContext, alloc, stride, xBytesSize, dimY, dimZ);
}
+ native void rsnAllocationSetupBufferQueue(long con, long alloc, int numAlloc);
+ synchronized void nAllocationSetupBufferQueue(long alloc, int numAlloc) {
+ validate();
+ rsnAllocationSetupBufferQueue(mContext, alloc, numAlloc);
+ }
+ native void rsnAllocationShareBufferQueue(long con, long alloc1, long alloc2);
+ synchronized void nAllocationShareBufferQueue(long alloc1, long alloc2) {
+ validate();
+ rsnAllocationShareBufferQueue(mContext, alloc1, alloc2);
+ }
native Surface rsnAllocationGetSurface(long con, long alloc);
synchronized Surface nAllocationGetSurface(long alloc) {
validate();
@@ -512,13 +521,12 @@
validate();
rsnAllocationIoSend(mContext, alloc);
}
- native void rsnAllocationIoReceive(long con, long alloc);
- synchronized void nAllocationIoReceive(long alloc) {
+ native long rsnAllocationIoReceive(long con, long alloc);
+ synchronized long nAllocationIoReceive(long alloc) {
validate();
- rsnAllocationIoReceive(mContext, alloc);
+ return rsnAllocationIoReceive(mContext, alloc);
}
-
native void rsnAllocationGenerateMipmaps(long con, long alloc);
synchronized void nAllocationGenerateMipmaps(long alloc) {
validate();
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 398d89b..3dff37b 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1223,6 +1223,27 @@
rsAllocationSyncAll((RsContext)con, (RsAllocation)a, (RsAllocationUsageType)bits);
}
+static void
+nAllocationSetupBufferQueue(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint numAlloc)
+{
+ if (kLogApi) {
+ ALOGD("nAllocationSetupBufferQueue, con(%p), alloc(%p), numAlloc(%d)", (RsContext)con,
+ (RsAllocation)alloc, numAlloc);
+ }
+ rsAllocationSetupBufferQueue((RsContext)con, (RsAllocation)alloc, (uint32_t)numAlloc);
+}
+
+static void
+nAllocationShareBufferQueue(JNIEnv *_env, jobject _this, jlong con, jlong alloc1, jlong alloc2)
+{
+ if (kLogApi) {
+ ALOGD("nAllocationShareBufferQueue, con(%p), alloc1(%p), alloc2(%p)", (RsContext)con,
+ (RsAllocation)alloc1, (RsAllocation)alloc2);
+ }
+
+ rsAllocationShareBufferQueue((RsContext)con, (RsAllocation)alloc1, (RsAllocation)alloc2);
+}
+
static jobject
nAllocationGetSurface(JNIEnv *_env, jobject _this, jlong con, jlong a)
{
@@ -1265,16 +1286,15 @@
rsAllocationIoSend((RsContext)con, (RsAllocation)alloc);
}
-static void
+static jlong
nAllocationIoReceive(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
{
if (kLogApi) {
ALOGD("nAllocationIoReceive, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
}
- rsAllocationIoReceive((RsContext)con, (RsAllocation)alloc);
+ return (jlong) rsAllocationIoReceive((RsContext)con, (RsAllocation)alloc);
}
-
static void
nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
{
@@ -2856,10 +2876,12 @@
{"rsnAllocationCopyToBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(JJI)V", (void*)nAllocationSyncAll },
+{"rsnAllocationSetupBufferQueue", "(JJI)V", (void*)nAllocationSetupBufferQueue },
+{"rsnAllocationShareBufferQueue", "(JJJ)V", (void*)nAllocationShareBufferQueue },
{"rsnAllocationGetSurface", "(JJ)Landroid/view/Surface;", (void*)nAllocationGetSurface },
{"rsnAllocationSetSurface", "(JJLandroid/view/Surface;)V", (void*)nAllocationSetSurface },
{"rsnAllocationIoSend", "(JJ)V", (void*)nAllocationIoSend },
-{"rsnAllocationIoReceive", "(JJ)V", (void*)nAllocationIoReceive },
+{"rsnAllocationIoReceive", "(JJ)J", (void*)nAllocationIoReceive },
{"rsnAllocationData1D", "(JJIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData1D },
{"rsnAllocationElementData", "(JJIIIII[BI)V", (void*)nAllocationElementData },
{"rsnAllocationData2D", "(JJIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData2D },
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 03809c0..53504cc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -27,6 +27,7 @@
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -51,6 +52,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -258,10 +260,9 @@
UserState userState = getCurrentUserStateLocked();
// We have to reload the installed services since some services may
// have different attributes, resolve info (does not support equals),
- // etc. Remove them then to force reload. Do it even if automation is
- // running since when it goes away, we will have to reload as well.
+ // etc. Remove them then to force reload.
userState.mInstalledServices.clear();
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
}
@@ -296,7 +297,7 @@
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
userState.mTouchExplorationGrantedServices, userId);
// We will update when the automation service dies.
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
onUserStateChangedLocked(userState);
}
return;
@@ -330,7 +331,7 @@
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
userState.mEnabledServices, userId);
// We will update when the automation service dies.
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
onUserStateChangedLocked(userState);
}
}
@@ -362,7 +363,7 @@
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
// We will update when the automation service dies.
UserState userState = getCurrentUserStateLocked();
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
}
@@ -473,11 +474,9 @@
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
- // The automation service is a fake one and should not be reported
- // to clients as being enabled. The automation service is always the
- // only active one, if it exists.
+ // The automation service can suppress other services.
UserState userState = getUserStateLocked(resolvedUserId);
- if (userState.mUiAutomationService != null) {
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return Collections.emptyList();
}
@@ -490,7 +489,9 @@
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
Service service = services.get(i);
- if ((service.mFeedbackType & feedbackTypeBit) != 0) {
+ // Don't report the UIAutomation (fake service)
+ if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
+ && (service.mFeedbackType & feedbackTypeBit) != 0) {
result.add(service.mAccessibilityServiceInfo);
}
}
@@ -621,7 +622,8 @@
@Override
public void registerUiTestAutomationService(IBinder owner,
IAccessibilityServiceClient serviceClient,
- AccessibilityServiceInfo accessibilityServiceInfo) {
+ AccessibilityServiceInfo accessibilityServiceInfo,
+ int flags) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
@@ -645,15 +647,17 @@
userState.mUiAutomationServiceOwner = owner;
userState.mUiAutomationServiceClient = serviceClient;
-
- // Set the temporary state.
+ userState.mUiAutomationFlags = flags;
userState.mIsAccessibilityEnabled = true;
- userState.mIsTouchExplorationEnabled = false;
- userState.mIsEnhancedWebAccessibilityEnabled = false;
- userState.mIsDisplayMagnificationEnabled = false;
- userState.mIsAutoclickEnabled = false;
userState.mInstalledServices.add(accessibilityServiceInfo);
- userState.mEnabledServices.clear();
+ if (userState.isUiAutomationSuppressingOtherServices()) {
+ // Set the temporary state.
+ userState.mIsTouchExplorationEnabled = false;
+ userState.mIsEnhancedWebAccessibilityEnabled = false;
+ userState.mIsDisplayMagnificationEnabled = false;
+ userState.mIsAutoclickEnabled = false;
+ userState.mEnabledServices.clear();
+ }
userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
@@ -694,7 +698,7 @@
UserState userState = getCurrentUserStateLocked();
// This is a nop if UI automation is enabled.
- if (userState.mUiAutomationService != null) {
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return;
}
@@ -954,7 +958,15 @@
final UserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
final Service service = state.mBoundServices.get(i);
- service.notifyMagnificationChanged(region, scale, centerX, centerY);
+ service.notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+ }
+
+ private void notifySoftKeyboardShowModeChangedLocked(int showMode) {
+ final UserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ final Service service = state.mBoundServices.get(i);
+ service.notifySoftKeyboardShowModeChangedLocked(showMode);
}
}
@@ -1027,6 +1039,9 @@
if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
userState.mEnabledServices.clear();
userState.mEnabledServices.addAll(mTempComponentNameSet);
+ if (userState.mUiAutomationService != null) {
+ userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
+ }
mTempComponentNameSet.clear();
return true;
}
@@ -1400,6 +1415,7 @@
updateEnhancedWebAccessibilityLocked(userState);
updateDisplayColorAdjustmentSettingsLocked(userState);
updateMagnificationLocked(userState);
+ updateSoftKeyboardShowModeLocked(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
@@ -1616,6 +1632,18 @@
return false;
}
+ private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) {
+ final int softKeyboardShowMode = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0,
+ userState.mUserId);
+ if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) {
+ userState.mSoftKeyboardShowMode = softKeyboardShowMode;
+ return true;
+ }
+ return false;
+ }
+
private void updateTouchExplorationLocked(UserState userState) {
boolean enabled = false;
final int serviceCount = userState.mBoundServices.size();
@@ -1750,6 +1778,25 @@
return false;
}
+ private void updateSoftKeyboardShowModeLocked(UserState userState) {
+ final int userId = userState.mUserId;
+ if (userId == mCurrentUserId) {
+ // Check whether any Accessibility Services are still enabled and, if not, remove flag
+ // requesting no soft keyboard
+ final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
+ if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+ // No active Accessibility Services can be requesting the soft keyboard to be hidden
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0,
+ userState.mUserId);
+ userState.mSoftKeyboardShowMode = 0;
+ }
+
+ notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
+ }
+ }
+
private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
@@ -2095,7 +2142,7 @@
};
// Handler for scheduling method invocations on the main thread.
- public InvocationHandler mInvocationHandler = new InvocationHandler(
+ public final InvocationHandler mInvocationHandler = new InvocationHandler(
mMainHandler.getLooper());
public Service(int userId, ComponentName componentName,
@@ -2290,17 +2337,20 @@
}
}
+ private boolean isCalledForCurrentUserLocked() {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
+ final int resolvedUserId = mSecurityPolicy
+ .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
+ return resolvedUserId == mCurrentUserId;
+ }
+
@Override
public List<AccessibilityWindowInfo> getWindows() {
ensureWindowsAvailableTimed();
synchronized (mLock) {
- // We treat calls from a profile as if made by its perent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2328,13 +2378,7 @@
public AccessibilityWindowInfo getWindow(int windowId) {
ensureWindowsAvailableTimed();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2361,13 +2405,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2418,13 +2456,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2475,13 +2507,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2532,13 +2558,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
@@ -2590,13 +2610,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2663,13 +2677,7 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2702,13 +2710,7 @@
@Override
public boolean performGlobalAction(int action) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
}
@@ -2743,13 +2745,7 @@
@Override
public float getMagnificationScale() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 1.0f;
}
}
@@ -2764,13 +2760,7 @@
@Override
public Region getMagnifiedRegion() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return Region.obtain();
}
}
@@ -2787,13 +2777,7 @@
@Override
public float getMagnificationCenterX() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2808,13 +2792,7 @@
@Override
public float getMagnificationCenterY() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2829,13 +2807,7 @@
@Override
public boolean resetMagnification(boolean animate) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2855,13 +2827,7 @@
public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
boolean animate) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2884,6 +2850,33 @@
}
@Override
+ public boolean setSoftKeyboardShowMode(int showMode) {
+ final UserState userState;
+ synchronized (mLock) {
+ if (!isCalledForCurrentUserLocked()) {
+ return false;
+ }
+
+ userState = getCurrentUserStateLocked();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ @Override
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
synchronized (mLock) {
@@ -3073,9 +3066,14 @@
InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
}
- public void notifyMagnificationChanged(@NonNull Region region,
+ public void notifyMagnificationChangedLocked(@NonNull Region region,
float scale, float centerX, float centerY) {
- mInvocationHandler.notifyMagnificationChanged(region, scale, centerX, centerY);
+ mInvocationHandler
+ .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
}
/**
@@ -3097,6 +3095,25 @@
}
}
+ /**
+ * Called by the invocation handler to notify the service that the state of the soft
+ * keyboard show mode has changed.
+ */
+ private void notifySoftKeyboardShowModeChangedInternal(int showState) {
+ final IAccessibilityServiceClient listener;
+ synchronized (mLock) {
+ listener = mServiceInterface;
+ }
+ if (listener != null) {
+ try {
+ listener.onSoftKeyboardShowModeChanged(showState);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
+ re);
+ }
+ }
+ }
+
private void notifyGestureInternal(int gestureId) {
final IAccessibilityServiceClient listener;
synchronized (mLock) {
@@ -3232,8 +3249,10 @@
public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
+ private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
private boolean mIsMagnificationCallbackEnabled = false;
+ private boolean mIsSoftKeyboardCallbackEnabled = false;
public InvocationHandler(Looper looper) {
super(looper, null, true);
@@ -3261,13 +3280,18 @@
notifyMagnificationChangedInternal(region, scale, centerX, centerY);
} break;
+ case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
+ final int showState = (int) message.arg1;
+ notifySoftKeyboardShowModeChangedInternal(showState);
+ } break;
+
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
}
}
- public void notifyMagnificationChanged(@NonNull Region region, float scale,
+ public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
float centerX, float centerY) {
if (!mIsMagnificationCallbackEnabled) {
// Callback is disabled, don't bother packing args.
@@ -3287,8 +3311,20 @@
public void setMagnificationCallbackEnabled(boolean enabled) {
mIsMagnificationCallbackEnabled = enabled;
}
- }
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ if (!mIsSoftKeyboardCallbackEnabled) {
+ return;
+ }
+
+ final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
+ msg.sendToTarget();
+ }
+
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mIsSoftKeyboardCallbackEnabled = enabled;
+ }
+ }
}
final class WindowsForAccessibilityCallback implements
@@ -3969,6 +4005,8 @@
public int mLastSentClientState = -1;
+ public int mSoftKeyboardShowMode = 0;
+
public boolean mIsAccessibilityEnabled;
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
@@ -3981,6 +4019,7 @@
public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
+ private int mUiAutomationFlags;
private IAccessibilityServiceClient mUiAutomationServiceClient;
private IBinder mUiAutomationServiceOwner;
@@ -4040,10 +4079,12 @@
mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
+ mSoftKeyboardShowMode = 0;
}
public void destroyUiAutomationService() {
mUiAutomationService = null;
+ mUiAutomationFlags = 0;
mUiAutomationServiceClient = null;
if (mUiAutomationServiceOwner != null) {
mUiAutomationServiceOwner.unlinkToDeath(
@@ -4051,6 +4092,11 @@
mUiAutomationServiceOwner = null;
}
}
+
+ boolean isUiAutomationSuppressingOtherServices() {
+ return ((mUiAutomationService != null) && (mUiAutomationFlags
+ & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0);
+ }
}
private final class AccessibilityContentObserver extends ContentObserver {
@@ -4091,6 +4137,9 @@
private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
+ private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+
public AccessibilityContentObserver(Handler handler) {
super(handler);
}
@@ -4121,6 +4170,8 @@
mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mHighTextContrastUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4130,8 +4181,8 @@
// we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
- // We will update when the automation service dies.
- if (userState.mUiAutomationService != null) {
+ // If the automation service is suppressing, we will update when it dies.
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return;
}
@@ -4175,6 +4226,10 @@
if (readHighTextContrastEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) {
+ if (readSoftKeyboardShowModeChangedLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 0513e53..c535ebd 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1049,7 +1049,9 @@
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
- mDataDir = Environment.getDownloadCacheDirectory();
+
+ // This dir on /cache is managed directly in init.rc
+ mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
mPasswordVersion = 1; // unless we hear otherwise
mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
@@ -8112,10 +8114,6 @@
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- if (!SELinux.restorecon(mBackupDataName)) {
- if (MORE_DEBUG) Slog.e(TAG, "SElinux restorecon failed for " + downloadFile);
- }
-
if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
// Transport-level failure, so we wind everything up and
// terminate the restore operation.
@@ -8169,6 +8167,7 @@
// Okay, we have the data. Now have the agent do the restore.
stage.close();
+
mBackupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
@@ -9056,25 +9055,30 @@
Slog.d(TAG, "fullTransportBackup()");
}
- CountDownLatch latch = new CountDownLatch(1);
- PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames,
- false, null, latch, null, false /* userInitiated */);
- // Acquiring wakelock for PerformFullTransportBackupTask before its start.
- mWakelock.acquire();
- (new Thread(task, "full-transport-master")).start();
- do {
- try {
- latch.await();
- break;
- } catch (InterruptedException e) {
- // Just go back to waiting for the latch to indicate completion
- }
- } while (true);
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ CountDownLatch latch = new CountDownLatch(1);
+ PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null,
+ pkgNames, false, null, latch, null, false /* userInitiated */);
+ // Acquiring wakelock for PerformFullTransportBackupTask before its start.
+ mWakelock.acquire();
+ (new Thread(task, "full-transport-master")).start();
+ do {
+ try {
+ latch.await();
+ break;
+ } catch (InterruptedException e) {
+ // Just go back to waiting for the latch to indicate completion
+ }
+ } while (true);
- // We just ran a backup on these packages, so kick them to the end of the queue
- final long now = System.currentTimeMillis();
- for (String pkg : pkgNames) {
- enqueueFullBackup(pkg, now);
+ // We just ran a backup on these packages, so kick them to the end of the queue
+ final long now = System.currentTimeMillis();
+ for (String pkg : pkgNames) {
+ enqueueFullBackup(pkg, now);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 666f2ff..aaa2211 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -12,4 +12,9 @@
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+ifneq ($(INCREMENTAL_BUILDS),)
+ LOCAL_PROGUARD_ENABLED := disabled
+ LOCAL_JACK_ENABLED := incremental
+endif
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e6e69b1..a4455e9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1181,6 +1181,9 @@
} else if ("audioserver".equals(packageName)) {
pkgUid = Process.AUDIOSERVER_UID;
isPrivileged = false;
+ } else if ("cameraserver".equals(packageName)) {
+ pkgUid = Process.CAMERASERVER_UID;
+ isPrivileged = false;
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3c13630..3fd8b40 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,6 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.annotation.Nullable;
-import android.app.AlarmManager;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
@@ -88,7 +87,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -115,7 +113,6 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.telephony.DctConstants;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -155,11 +152,9 @@
import java.util.HashSet;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -745,7 +740,7 @@
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
&& SystemProperties.get("ro.build.type").equals("eng");
- mTethering = new Tethering(mContext, mNetd, statsService, mHandler.getLooper());
+ mTethering = new Tethering(mContext, mNetd, statsService);
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -2186,7 +2181,7 @@
if (wasDefault) {
mDefaultInetConditionPublished = 0;
}
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
// by other networks that are already connected. Perhaps that can be done by
// sending all CALLBACK_LOST messages (for requests, not listens) at the end
@@ -3800,6 +3795,12 @@
throw new IllegalArgumentException("Bad timeout specified");
}
+ if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER
+ .equals(networkCapabilities.getNetworkSpecifier())) {
+ throw new IllegalArgumentException("Invalid network specifier - must not be '"
+ + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+ }
+
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
@@ -4089,7 +4090,7 @@
}
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -4713,7 +4714,11 @@
notifyLockdownVpn(networkAgent);
if (oldInfo != null && oldInfo.getState() == state) {
- if (VDBG) log("ignoring duplicate network state non-change");
+ if (oldInfo.isRoaming() != newInfo.isRoaming()) {
+ if (VDBG) log("roaming status changed, notifying NetworkStatsService");
+ notifyIfacesChangedForNetworkStats();
+ } else if (VDBG) log("ignoring duplicate network state non-change");
+ // In either case, no further work should be needed.
return;
}
if (DBG) {
@@ -4743,7 +4748,7 @@
}
networkAgent.created = true;
updateLinkProperties(networkAgent, null);
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
scheduleUnvalidatedPrompt(networkAgent);
@@ -4907,9 +4912,10 @@
}
/**
- * Notify other system services that set of active ifaces has changed.
+ * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
+ * properties tracked by NetworkStatsService on an active iface has changed.
*/
- private void notifyIfacesChanged() {
+ private void notifyIfacesChangedForNetworkStats() {
try {
mStatsService.forceUpdateIfaces();
} catch (Exception ignored) {
@@ -4943,7 +4949,7 @@
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
}
return success;
}
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index bc12fc5..9313148 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -21,6 +21,7 @@
import android.os.Environment;
import android.os.StatFs;
import android.os.SystemClock;
+import android.os.storage.StorageManager;
import java.io.File;
import java.io.FileDescriptor;
@@ -79,6 +80,10 @@
reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
reportFreeSpace(new File("/system"), "System", pw);
+ if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+ pw.println("File-based Encryption: true");
+ }
+
// TODO: Read /proc/yaffs and report interesting values;
// add configurable (through args) performance test parameters.
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 2aa0390..d6575e8 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,6 +38,7 @@
import android.view.KeyEvent;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.server.statusbar.StatusBarManagerInternal;
/**
@@ -270,7 +271,7 @@
launched = handleCameraLaunchGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) doubleTapInterval);
}
}
@@ -341,7 +342,7 @@
}
if (handleCameraLaunchGesture(true /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
}
return;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4a123df..d77def6 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -448,6 +448,7 @@
private int[] mSubtypeIds;
private Locale mLastSystemLocale;
private boolean mShowImeWithHardKeyboard;
+ private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
private final String mSlotIme;
@@ -485,15 +486,31 @@
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
mRegistered = true;
}
@Override public void onChange(boolean selfChange, Uri uri) {
- final Uri showImeUri =
- Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri showImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
synchronized (mMethodMap) {
if (showImeUri.equals(uri)) {
updateKeyboardFromSettingsLocked();
+ } else if (accessibilityRequestingNoImeUri.equals(uri)) {
+ mAccessibilityRequestingNoSoftKeyboard = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0, mUserId) == 1;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ final boolean showRequested = mShowRequested;
+ hideCurrentInputLocked(0, null);
+ mShowRequested = showRequested;
+ } else if (mShowRequested) {
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ }
} else {
boolean enabledChanged = false;
String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -655,7 +672,7 @@
boolean changed = false;
if (curIm != null) {
- int change = isPackageDisappearing(curIm.getPackageName());
+ int change = isPackageDisappearing(curIm.getPackageName());
if (change == PACKAGE_TEMPORARY_CHANGE
|| change == PACKAGE_PERMANENT_CHANGE) {
ServiceInfo si = null;
@@ -2073,12 +2090,15 @@
boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
mShowRequested = true;
- if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
- mShowExplicitlyRequested = true;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ return false;
}
+
if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
mShowExplicitlyRequested = true;
mShowForced = true;
+ } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
+ mShowExplicitlyRequested = true;
}
if (!mSystemReady) {
@@ -3265,7 +3285,7 @@
"Requires permission "
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
-
+
long ident = Binder.clearCallingIdentity();
try {
return setInputMethodEnabledLocked(id, enabled);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9405d8e0..c55c5b6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -24,10 +24,10 @@
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.FlpHardwareProvider;
import com.android.server.location.FusedProxy;
+import com.android.server.location.GnssLocationProvider;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GeofenceProxy;
-import com.android.server.location.GpsLocationProvider;
import com.android.server.location.GpsMeasurementsProvider;
import com.android.server.location.GpsNavigationMessageProvider;
import com.android.server.location.LocationBlacklist;
@@ -61,11 +61,11 @@
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
@@ -157,7 +157,7 @@
private PowerManager mPowerManager;
private UserManager mUserManager;
private GeocoderProxy mGeocodeProvider;
- private IGpsStatusProvider mGpsStatusProvider;
+ private IGnssStatusProvider mGnssStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
@@ -214,6 +214,8 @@
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
+ private GnssLocationProvider.GpsSystemInfoProvider mGpsSystemInfoProvider;
+
public LocationManagerService(Context context) {
super();
mContext = context;
@@ -456,17 +458,18 @@
mEnabledProviders.add(passiveProvider.getName());
mPassiveProvider = passiveProvider;
- if (GpsLocationProvider.isSupported()) {
+ if (GnssLocationProvider.isSupported()) {
// Create a gps location provider
- GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
+ GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
- mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
- mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
- addProviderLocked(gpsProvider);
- mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
- mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
- mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
- mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
+ mGpsSystemInfoProvider = gnssProvider.getGpsSystemInfoProvider();
+ mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
+ mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
+ addProviderLocked(gnssProvider);
+ mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
+ mGpsMeasurementsProvider = gnssProvider.getGpsMeasurementsProvider();
+ mGpsNavigationMessageProvider = gnssProvider.getGpsNavigationMessageProvider();
+ mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
}
/*
@@ -986,6 +989,18 @@
}
}
+ /**
+ * Returns the system information of the GPS hardware.
+ */
+ @Override
+ public int getGpsYearOfHardware() {
+ if (mGpsNavigationMessageProvider != null) {
+ return mGpsSystemInfoProvider.getGpsYearOfHardware();
+ } else {
+ return 0;
+ }
+ }
+
private void addProviderLocked(LocationProviderInterface provider) {
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
@@ -1867,7 +1882,7 @@
@Override
- public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
+ public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
LocationManager.GPS_PROVIDER);
@@ -1883,26 +1898,26 @@
Binder.restoreCallingIdentity(ident);
}
- if (mGpsStatusProvider == null) {
+ if (mGnssStatusProvider == null) {
return false;
}
try {
- mGpsStatusProvider.addGpsStatusListener(listener);
+ mGnssStatusProvider.registerGnssStatusCallback(callback);
} catch (RemoteException e) {
- Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
+ Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
return false;
}
return true;
}
@Override
- public void removeGpsStatusListener(IGpsStatusListener listener) {
+ public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
synchronized (mLock) {
try {
- mGpsStatusProvider.removeGpsStatusListener(listener);
+ mGnssStatusProvider.unregisterGnssStatusCallback(callback);
} catch (Exception e) {
- Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
+ Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
}
}
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f6f05fe..d0cd536 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,11 +17,12 @@
package com.android.server;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
import android.app.trust.IStrongAuthTracker;
-import android.app.trust.ITrustManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -30,6 +31,8 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
+
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_CONTACTS;
@@ -40,7 +43,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -70,19 +72,27 @@
* @hide
*/
public class LockSettingsService extends ILockSettings.Stub {
-
- private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
-
private static final String TAG = "LockSettingsService";
+ private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+ private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
+ private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
+ private static final boolean DEBUG = false;
private final Context mContext;
-
private final LockSettingsStorage mStorage;
private final LockSettingsStrongAuth mStrongAuth;
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
private IGateKeeperService mGateKeeperService;
+ private NotificationManager mNotificationManager;
+ private UserManager mUserManager;
+
+ static {
+ // Just launch the home screen, which happens anyway
+ ACTION_NULL = new Intent(Intent.ACTION_MAIN);
+ ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
+ }
private interface CredentialUtil {
void setCredential(String credential, String savedCredential, int userId)
@@ -91,6 +101,42 @@
String adjustForKeystore(String credential);
}
+ // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
+ // devices. The most basic of these is to show/hide notifications about missing features until
+ // the user unlocks the account and credential-encrypted storage is available.
+ public static final class Lifecycle extends SystemService {
+ private LockSettingsService mLockSettingsService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mLockSettingsService = new LockSettingsService(getContext());
+ publishBinderService("lock_settings", mLockSettingsService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ // TODO
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mLockSettingsService.onUnlockUser(userHandle);
+ }
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ mLockSettingsService.onCleanupUser(userHandle);
+ }
+ }
+
public LockSettingsService(Context context) {
mContext = context;
mStrongAuth = new LockSettingsStrongAuth(context);
@@ -117,6 +163,71 @@
}
}
});
+ mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+
+ /**
+ * If the account is credential-encrypted, show notification requesting the user to unlock
+ * the device.
+ */
+ private void maybeShowEncryptionNotification(UserHandle userHandle) {
+ if (UserHandle.ALL.equals(userHandle)) {
+ final List<UserInfo> users = mUserManager.getUsers();
+ for (int i = 0; i < users.size(); i++) {
+ UserHandle user = users.get(i).getUserHandle();
+ if (!mUserManager.isUserUnlocked(user)) {
+ showEncryptionNotification(user);
+ }
+ }
+ } else if (!mUserManager.isUserUnlocked(userHandle)){
+ showEncryptionNotification(userHandle);
+ }
+ }
+
+ private void showEncryptionNotification(UserHandle user) {
+ if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.user_encrypted_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.user_encrypted_message);
+ CharSequence detail = r.getText(
+ com.android.internal.R.string.user_encrypted_detail);
+
+ PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(com.android.internal.R.drawable.ic_secure)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setDefaults(0) // please be quiet
+ .setPriority(Notification.PRIORITY_MAX)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setContentInfo(detail)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(intent)
+ .build();
+ mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
+ }
+
+ public void hideEncryptionNotification(UserHandle userHandle) {
+ if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
+ mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
+ }
+
+ public void onCleanupUser(int userId) {
+ hideEncryptionNotification(new UserHandle(userId));
+ }
+
+ public void onUnlockUser(int userHandle) {
+ hideEncryptionNotification(new UserHandle(userHandle));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -144,6 +255,7 @@
}
};
+ @Override // binder interface
public void systemReady() {
migrateOldData();
try {
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
new file mode 100644
index 0000000..0610464
--- /dev/null
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+public class SensorNotificationService extends SystemService implements SensorEventListener {
+ //TODO: set DBG to false or remove Slog before release
+ private static final boolean DBG = true;
+ private static final String TAG = "SensorNotificationService";
+ private Context mContext;
+
+ private SensorManager mSensorManager;
+ private Sensor mMetaSensor;
+
+ public SensorNotificationService(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ public void onStart() {
+ LocalServices.addService(SensorNotificationService.class, this);
+ }
+
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // start
+ mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+ mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META);
+ if (mMetaSensor == null) {
+ if (DBG) Slog.d(TAG, "Cannot obtain dynamic meta sensor, not supported.");
+ } else {
+ mSensorManager.registerListener(this, mMetaSensor,
+ SensorManager.SENSOR_DELAY_FASTEST);
+ }
+ }
+ }
+
+ private void broadcastDynamicSensorChanged() {
+ Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
+ i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers
+ mContext.sendBroadcastAsUser(i, UserHandle.ALL);
+ if (DBG) Slog.d(TAG, "DYNS sent dynamic sensor broadcast");
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor == mMetaSensor) {
+ broadcastDynamicSensorChanged();
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+}
+
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 4dc46ac..5aba22d 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -16,20 +16,24 @@
package com.android.server;
+import static com.android.internal.util.ArrayUtils.appendInt;
+
import android.app.ActivityManager;
import android.content.pm.FeatureInfo;
-import android.os.*;
+import android.content.pm.PackageManager;
+import android.os.Environment;
import android.os.Process;
+import android.os.storage.StorageManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
-import libcore.io.IoUtils;
-
import com.android.internal.util.XmlUtils;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -38,8 +42,6 @@
import java.io.FileReader;
import java.io.IOException;
-import static com.android.internal.util.ArrayUtils.appendInt;
-
/**
* Loads global system configuration info.
*/
@@ -351,10 +353,7 @@
Slog.w(TAG, "<feature> without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (allowed) {
- //Log.i(TAG, "Got feature " + fname);
- FeatureInfo fi = new FeatureInfo();
- fi.name = fname;
- mAvailableFeatures.put(fname, fi);
+ addFeature(fname);
}
XmlUtils.skipCurrentTag(parser);
continue;
@@ -443,10 +442,29 @@
IoUtils.closeQuietly(permReader);
}
- for (String fname : mUnavailableFeatures) {
- if (mAvailableFeatures.remove(fname) != null) {
- Slog.d(TAG, "Removed unavailable feature " + fname);
- }
+ // Some devices can be field-converted to FBE, so offer to splice in
+ // those features if not already defined by the static config
+ if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+ addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION);
+ addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS);
+ }
+
+ for (String featureName : mUnavailableFeatures) {
+ removeFeature(featureName);
+ }
+ }
+
+ private void addFeature(String featureName) {
+ if (!mAvailableFeatures.containsKey(featureName)) {
+ final FeatureInfo fi = new FeatureInfo();
+ fi.name = featureName;
+ mAvailableFeatures.put(featureName, fi);
+ }
+ }
+
+ private void removeFeature(String featureName) {
+ if (mAvailableFeatures.remove(featureName) != null) {
+ Slog.d(TAG, "Removed unavailable feature " + featureName);
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d0006aa..143015f 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4342,6 +4342,7 @@
String opPackageName) {
List<String> permissionsToCheck = new ArrayList<String>(2);
permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+ long id = Binder.clearCallingIdentity();
try {
ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
opPackageName, 0 /* flags */);
@@ -4363,6 +4364,8 @@
} catch (NameNotFoundException e) {
// No application associated with the specified package.
Log.w(TAG, "No application associated with package: " + opPackageName);
+ } finally {
+ Binder.restoreCallingIdentity(id);
}
boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck);
return getTypesForCaller(callingUid, userId, isPermitted);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2c55ee2..978e69c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8591,6 +8591,7 @@
if (tr.mBounds != null) {
rti.bounds = new Rect(tr.mBounds);
}
+ rti.isDockable = tr.canGoInDockedStack();
ActivityRecord base = null;
ActivityRecord top = null;
@@ -8875,7 +8876,7 @@
}
@Override
- public void setTaskResizeable(int taskId, boolean resizeable) {
+ public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
@@ -8883,9 +8884,9 @@
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
}
- if (task.mResizeable != resizeable) {
- task.mResizeable = resizeable;
- mWindowManager.setTaskResizeable(taskId, resizeable);
+ if (task.mResizeMode != resizeableMode) {
+ task.mResizeMode = resizeableMode;
+ mWindowManager.setTaskResizeable(taskId, resizeableMode);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -8904,10 +8905,10 @@
return;
}
int stackId = task.stack.mStackId;
- // First, check if this is a non-resizeble task in docked stack or if the task size
- // is affected by the docked stack changing size. If so, instead of resizing, we
- // can only scroll the task. No need to update configuration.
- if (bounds != null && !task.mResizeable
+ // We allow the task to scroll instead of resizing if this is a non-resizeable task
+ // in crop windows resize mode or if the task size is affected by the docked stack
+ // changing size. No need to update configuration.
+ if (bounds != null && task.inCropWindowsResizeMode()
&& mStackSupervisor.isStackDockedInEffect(stackId)) {
mWindowManager.scrollTask(task.taskId, bounds);
return;
@@ -9411,14 +9412,24 @@
}
@Override
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- mStackSupervisor.resizeStackLocked(
- stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- !PRESERVE_WINDOWS, allowResizeInDockedMode);
+ if (animate) {
+ if (stackId == PINNED_STACK_ID) {
+ mWindowManager.animateResizePinnedStack(bounds);
+ } else {
+ throw new IllegalArgumentException("Stack: " + stackId
+ + " doesn't support animated resize.");
+ }
+ } else {
+ mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, preserveWindows,
+ allowResizeInDockedMode);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12154,6 +12165,7 @@
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
mForceResizableActivities = forceResizable;
+ mWindowManager.setForceResizableTasks(mForceResizableActivities);
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
// This happens before any activities are started, so we can
@@ -12960,6 +12972,11 @@
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, processName, sb);
+ if (process != null) {
+ sb.append("Foreground: ")
+ .append(process.isInterestingToUserLocked() ? "Yes" : "No")
+ .append("\n");
+ }
if (activity != null) {
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 71008a9..ed26e0c 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -18,9 +18,9 @@
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
-import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -355,6 +355,9 @@
if (connections != null) {
pw.print(prefix); pw.print("connections="); pw.println(connections);
}
+ if (info != null) {
+ pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+ }
}
public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
@@ -754,11 +757,20 @@
}
boolean isResizeable() {
- return (info.flags & FLAG_RESIZEABLE) != 0;
+ return !isHomeActivity() && ActivityInfo.isResizeableMode(info.resizeMode);
+ }
+
+ boolean isResizeableOrForced() {
+ return !isHomeActivity() && (isResizeable() || service.mForceResizableActivities);
}
boolean supportsPictureInPicture() {
- return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+ return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ }
+
+ boolean canGoInDockedStack() {
+ return !isHomeActivity()
+ && (isResizeableOrForced() || info.resizeMode == RESIZE_MODE_CROP_WINDOWS);
}
boolean isAlwaysFocusable() {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ef8d230..7de254e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1410,14 +1410,11 @@
}
if (mStackId == DOCKED_STACK_ID) {
- // Docked stack is always visible, except in the case where the home activity
- // is the top running activity in the focused home stack.
- if (focusedStackId != HOME_STACK_ID) {
- return STACK_VISIBLE;
- }
- ActivityRecord topHomeActivity = focusedStack.topRunningActivityLocked();
- return topHomeActivity == null || !topHomeActivity.isHomeActivity() ?
- STACK_VISIBLE : STACK_INVISIBLE;
+ // Docked stack is always visible, except in the case where the top running activity
+ // task in the focus stack doesn't support any form of resizing.
+ final ActivityRecord r = focusedStack.topRunningActivityLocked();
+ final TaskRecord task = r != null ? r.task : null;
+ return task == null || task.canGoInDockedStack() ? STACK_VISIBLE : STACK_INVISIBLE;
}
// Find the first stack below focused stack that actually got something visible.
@@ -4545,6 +4542,7 @@
}
ci.numActivities = numActivities;
ci.numRunning = numRunning;
+ ci.isDockable = task.canGoInDockedStack();
list.add(ci);
}
}
@@ -4754,7 +4752,7 @@
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
- if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.mResizeable
+ if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.isResizeable()
&& !isLockscreenShown) {
task.updateOverrideConfiguration(mBounds);
}
@@ -4819,8 +4817,7 @@
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
- !r.isHomeActivity(), r.isAlwaysFocusable());
- mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
+ task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask());
r.taskConfigOverride = task.mOverrideConfig;
}
@@ -4872,9 +4869,8 @@
private void setAppTask(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
- mWindowManager.setAppTask(
- r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig);
- mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
+ mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig,
+ task.mResizeMode, task.isHomeTask());
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8db2f8f..7359859 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import static android.Manifest.permission.START_ANY_ACTIVITY;
@@ -118,6 +119,7 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -1712,7 +1714,7 @@
return;
}
- if (task.mResizeable && options != null) {
+ if (task.isResizeable() && options != null) {
int stackId = options.getLaunchStackId();
if (canUseActivityOptionsLaunchBounds(options, stackId)) {
final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
@@ -1721,7 +1723,9 @@
stackId = task.getLaunchStackId();
}
if (stackId != task.stack.mStackId) {
- moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+ final ActivityStack stack = moveTaskToStackUncheckedLocked(
+ task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+ stackId = stack.mStackId;
// moveTaskToStackUncheckedLocked() should already placed the task on top,
// still need moveTaskToFrontLocked() below for any transition settings.
}
@@ -1894,10 +1898,10 @@
mTmpBounds.clear();
mTmpConfigs.clear();
mTmpInsetBounds.clear();
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
- TaskRecord task = tasks.get(i);
- if (task.mResizeable) {
+ final TaskRecord task = tasks.get(i);
+ if (task.isResizeable()) {
if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
// For freeform stack we don't adjust the size of the tasks to match that
// of the stack, but we do try to make sure the tasks are still contained
@@ -2009,7 +2013,7 @@
}
boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
- if (!task.mResizeable) {
+ if (!task.isResizeable()) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
return true;
}
@@ -2019,7 +2023,7 @@
// If this is a forced resize, let it go through even if the bounds is not changing,
// as we might need a relayout due to surface size change (to/from fullscreen).
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
- if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
+ if (Objects.equals(task.mBounds, bounds) && !forced) {
// Nothing to do here...
return true;
}
@@ -2131,7 +2135,12 @@
private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
if (stackId == INVALID_STACK_ID) {
stackId = task.getLaunchStackId();
+ } else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) {
+ // Preferred stack is the docked stack, but the task can't go in the docked stack.
+ // Put it in the fullscreen stack.
+ stackId = FULLSCREEN_WORKSPACE_STACK_ID;
}
+
if (task.stack != null) {
// Task has already been restored once. See if we need to do anything more
if (task.stack.mStackId == stackId) {
@@ -2167,8 +2176,7 @@
* Moves the specified task record to the input stack id.
* WARNING: This method performs an unchecked/raw move of the task and
* can leave the system in an unstable state if used incorrectly.
- * Use {@link #moveTaskToStackLocked} to perform safe task movement
- * to a stack.
+ * Use {@link #moveTaskToStackLocked} to perform safe task movement to a stack.
* @param task Task to move.
* @param stackId Id of stack to move task to.
* @param toTop True if the task should be placed at the top of the stack.
@@ -2188,13 +2196,24 @@
final boolean wasFront = isFrontStack(prevStack)
&& (prevStack.topRunningActivityLocked() == r);
- final boolean resizeable = task.mResizeable;
+ final int resizeMode = task.mResizeMode;
+
+ if (stackId == DOCKED_STACK_ID && resizeMode == RESIZE_MODE_UNRESIZEABLE) {
+ // We don't allow moving a unresizeable task to the docked stack since the docked
+ // stack is used for split-screen mode and will cause things like the docked divider to
+ // show up. We instead leave the task in its current stack or move it to the fullscreen
+ // stack if it isn't currently in a stack.
+ stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID;
+ Slog.w(TAG, "Can not move unresizeable task=" + task
+ + " to docked stack. Moving to stackId=" + stackId + " instead.");
+ }
+
// Temporarily disable resizeablility of task we are moving. We don't want it to be resized
// if a docked stack is created below which will lead to the stack we are moving from and
// its resizeable tasks being resized.
- task.mResizeable = false;
+ task.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
- task.mResizeable = resizeable;
+ task.mResizeMode = resizeMode;
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
stack.addTask(task, toTop, reason);
@@ -2234,8 +2253,10 @@
// during the relaunch. If we end up not doing any relaunch, we clear the flags later.
mWindowManager.setReplacingWindow(topActivity.appToken, animate);
}
+ final int preferredLaunchStackId = stackId;
final ActivityStack stack = moveTaskToStackUncheckedLocked(
task, stackId, toTop, forceFocus, "moveTaskToStack:" + reason);
+ stackId = stack.mStackId;
if (!animate) {
stack.mNoAnimActivities.add(topActivity);
@@ -2257,10 +2278,7 @@
// If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
// window), we need to clear the replace window settings. Otherwise, we schedule a
// timeout to remove the old window if the replacing window is not coming in time.
- // In case of the pinned stack we don't resize the task during the move, but we will
- // resize the stack soon after so we want to retain the replacing window.
- mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken,
- !kept || stackId == PINNED_STACK_ID);
+ mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
}
// The task might have already been running and its visibility needs to be synchronized with
@@ -2268,9 +2286,7 @@
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- if (!task.mResizeable && isStackDockedInEffect(stackId)) {
- showNonResizeableDockToast(taskId);
- }
+ showNonResizeableDockToastIfNeeded(task, preferredLaunchStackId, stackId);
}
boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
@@ -2294,7 +2310,8 @@
return false;
}
- moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", bounds);
+ moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
+ mWindowManager.animateResizePinnedStack(bounds);
return true;
}
@@ -3221,8 +3238,17 @@
}
}
- void showNonResizeableDockToast(int taskId) {
- mWindowManager.scheduleShowNonResizeableDockToast(taskId);
+ void showNonResizeableDockToastIfNeeded(
+ TaskRecord task, int preferredStackId, int actualStackId) {
+ if (!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID) {
+ return;
+ }
+
+ if (!task.canGoInDockedStack() || task.inCropWindowsResizeMode()) {
+ // Display warning toast if we tried to put a non-dockable task in the docked stack or
+ // the task is running in cropped window mode.
+ mWindowManager.scheduleShowNonResizeableDockToast(task.taskId);
+ }
}
void showLockTaskToast() {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7b7359f..4015c08 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1004,10 +1004,10 @@
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
- if (!mStartActivity.task.mResizeable
- && mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
- mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
- }
+ final int preferredLaunchStackId =
+ (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
+ mSupervisor.showNonResizeableDockToastIfNeeded(
+ mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
return START_SUCCESS;
}
@@ -1484,8 +1484,9 @@
mInTask.updateOverrideConfiguration(mLaunchBounds);
int stackId = mInTask.getLaunchStackId();
if (stackId != mInTask.stack.mStackId) {
- mSupervisor.moveTaskToStackUncheckedLocked(
+ final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+ stackId = stack.mStackId;
}
if (StackId.resizeStackWithLaunchBounds(stackId)) {
mSupervisor.resizeStackLocked(stackId, mLaunchBounds,
@@ -1627,10 +1628,9 @@
// If the freeform or docked stack has focus, and the activity to be launched is resizeable,
// we can also put it in the focused stack.
final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
- final boolean canUseFocusedStack =
- focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
- || focusedStackId == DOCKED_STACK_ID
- || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeable());
+ final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
+ || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack())
+ || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced());
if (canUseFocusedStack && (!newTask
|| mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
@@ -1666,6 +1666,10 @@
if (isValidLaunchStackId(launchStackId, r)) {
return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
+ } else if (launchStackId == DOCKED_STACK_ID) {
+ // The preferred launch stack is the docked stack, but it isn't a valid launch stack
+ // for this activity, so we put the activity in the fullscreen stack.
+ return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
@@ -1701,9 +1705,11 @@
return false;
}
- final boolean resizeable = r.isResizeable() || mService.mForceResizableActivities;
+ if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
+ return true;
+ }
- if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !resizeable) {
+ if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !r.isResizeableOrForced()) {
return false;
}
@@ -1721,7 +1727,7 @@
Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
Rect newBounds = null;
- if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+ if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
if (mSupervisor.canUseActivityOptionsLaunchBounds(
options, options.getLaunchStackId())) {
newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 58d9f45..190e9e1 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -745,7 +745,8 @@
if (mService.mController != null) {
try {
// 0 == continue, -1 = kill process immediately
- int res = mService.mController.appEarlyNotResponding(app.processName, app.pid, annotation);
+ int res = mService.mController.appEarlyNotResponding(
+ app.processName, app.pid, annotation);
if (res < 0 && app.pid != MY_PID) {
app.kill("anr", true);
}
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 4587b72..9875887 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -21,12 +21,19 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.TextView;
-final class AppNotRespondingDialog extends BaseErrorDialog {
+import static com.android.server.am.ActivityManagerService.IS_USER_BUILD;
+
+final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnClickListener {
private static final String TAG = "AppNotRespondingDialog";
// Event 'what' codes
@@ -36,15 +43,15 @@
private final ActivityManagerService mService;
private final ProcessRecord mProc;
-
+
public AppNotRespondingDialog(ActivityManagerService service, Context context,
ProcessRecord app, ActivityRecord activity, boolean aboveSystem) {
super(context);
-
+
mService = service;
mProc = app;
Resources res = context.getResources();
-
+
setCancelable(false);
int resid;
@@ -71,24 +78,10 @@
}
}
- setMessage(name2 != null
+ setTitle(name2 != null
? res.getString(resid, name1.toString(), name2.toString())
: res.getString(resid, name1.toString()));
- setButton(DialogInterface.BUTTON_POSITIVE,
- res.getText(com.android.internal.R.string.force_close),
- mHandler.obtainMessage(FORCE_CLOSE));
- setButton(DialogInterface.BUTTON_NEGATIVE,
- res.getText(com.android.internal.R.string.wait),
- mHandler.obtainMessage(WAIT));
-
- if (app.errorReportReceiver != null) {
- setButton(DialogInterface.BUTTON_NEUTRAL,
- res.getText(com.android.internal.R.string.report),
- mHandler.obtainMessage(WAIT_AND_REPORT));
- }
-
- setTitle(res.getText(com.android.internal.R.string.anr_title));
if (aboveSystem) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
}
@@ -99,7 +92,41 @@
getWindow().setAttributes(attrs);
}
- public void onStop() {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final FrameLayout frame = (FrameLayout) findViewById(android.R.id.custom);
+ final Context context = getContext();
+ LayoutInflater.from(context).inflate(
+ com.android.internal.R.layout.app_anr_dialog, frame, true);
+
+ final TextView report = (TextView) findViewById(com.android.internal.R.id.aerr_report);
+ report.setOnClickListener(this);
+ final boolean hasReceiver = mProc.errorReportReceiver != null;
+ report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE);
+ final TextView close = (TextView) findViewById(com.android.internal.R.id.aerr_close);
+ close.setOnClickListener(this);
+ final TextView wait = (TextView) findViewById(com.android.internal.R.id.aerr_wait);
+ wait.setOnClickListener(this);
+
+ findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case com.android.internal.R.id.aerr_report:
+ mHandler.obtainMessage(WAIT_AND_REPORT).sendToTarget();
+ break;
+ case com.android.internal.R.id.aerr_close:
+ mHandler.obtainMessage(FORCE_CLOSE).sendToTarget();
+ break;
+ case com.android.internal.R.id.aerr_wait:
+ mHandler.obtainMessage(WAIT).sendToTarget();
+ break;
+ default:
+ break;
+ }
}
private final Handler mHandler = new Handler() {
@@ -138,6 +165,8 @@
Slog.w(TAG, "bug report receiver dissappeared", e);
}
}
+
+ dismiss();
}
};
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 82862e8..97ef10b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -40,6 +40,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.IntArray;
@@ -51,6 +52,7 @@
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.internal.telephony.ITelephony;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -855,6 +857,18 @@
}
}
+ @Override
+ public void noteBleScanStarted(WorkSource ws) {
+ enforceCallingPermission();
+ Slog.d(TAG, "BLE scan started for " + ws);
+ }
+
+ @Override
+ public void noteBleScanStopped(WorkSource ws) {
+ enforceCallingPermission();
+ Slog.d(TAG, "BLE scan stopped for " + ws);
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
@@ -1317,6 +1331,24 @@
return null;
}
+ @GuardedBy("mExternalStatsLock")
+ private ModemActivityInfo pullModemActivityInfoLocked() {
+ ITelephony tm = ITelephony.Stub.asInterface(ServiceManager.getService(
+ Context.TELEPHONY_SERVICE));
+ try {
+ if (tm != null) {
+ ModemActivityInfo info = tm.getModemActivityInfo();
+ if (info == null || info.isValid()) {
+ return info;
+ }
+ Slog.wtf(TAG, "Modem activity info is invalid: " + info);
+ }
+ } catch (RemoteException e) {
+ // Nothing to do.
+ }
+ return null;
+ }
+
/**
* Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
* batterystats with that information.
@@ -1346,6 +1378,11 @@
wifiEnergyInfo = pullWifiEnergyInfoLocked();
}
+ ModemActivityInfo modemActivityInfo = null;
+ if ((updateFlags & UPDATE_RADIO) != 0) {
+ modemActivityInfo = pullModemActivityInfoLocked();
+ }
+
BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
if ((updateFlags & UPDATE_BT) != 0) {
// We only pull bluetooth stats when we have to, as we are not distributing its
@@ -1367,7 +1404,7 @@
}
if ((updateFlags & UPDATE_RADIO) != 0) {
- mStats.updateMobileRadioStateLocked(elapsedRealtime);
+ mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo);
}
if ((updateFlags & UPDATE_WIFI) != 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index fd787df..be97c5a 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -24,7 +24,9 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -117,7 +119,10 @@
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
private static final String ATTR_CALLING_UID = "calling_uid";
private static final String ATTR_CALLING_PACKAGE = "calling_package";
+ // TODO(b/26847884): Currently needed while migrating to resize_mode.
+ // Can be removed at some later point.
private static final String ATTR_RESIZEABLE = "resizeable";
+ private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
@@ -155,8 +160,8 @@
int numFullscreen; // Number of fullscreen activities.
- boolean mResizeable; // Activities in the task resizeable. Based on the resizable setting of
- // the root activity.
+ int mResizeMode; // The resize mode of this task and its activities.
+ // Based on the {@link ActivityInfo#resizeMode} of the root activity.
int mLockTaskMode; // Which tasklock mode to launch this task in. One of
// ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
@@ -308,7 +313,7 @@
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- boolean resizeable, boolean privileged, boolean realActivitySuspended) {
+ int resizeMode, boolean privileged, boolean _realActivitySuspended) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -322,7 +327,7 @@
voiceSession = null;
voiceInteractor = null;
realActivity = _realActivity;
- realActivitySuspended = realActivitySuspended;
+ realActivitySuspended = _realActivitySuspended;
origActivity = _origActivity;
rootWasReset = _rootWasReset;
isAvailable = true;
@@ -345,7 +350,7 @@
mNextAffiliateTaskId = nextTaskId;
mCallingUid = callingUid;
mCallingPackage = callingPackage;
- mResizeable = resizeable || mService.mForceResizableActivities;
+ mResizeMode = resizeMode;
mPrivileged = privileged;
ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null;
mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
@@ -447,7 +452,7 @@
} else {
autoRemoveRecents = false;
}
- mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities;
+ mResizeMode = info.resizeMode;
mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
setLockTaskAuth();
@@ -702,9 +707,6 @@
// Only set this based on the first activity
if (mActivities.isEmpty()) {
taskType = r.mActivityType;
- if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
- mResizeable = r.isResizeable();
- }
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
@@ -932,6 +934,19 @@
return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
}
+ boolean isResizeable() {
+ return !isHomeTask() && (mService.mForceResizableActivities
+ || ActivityInfo.isResizeableMode(mResizeMode));
+ }
+
+ boolean inCropWindowsResizeMode() {
+ return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
+ }
+
+ boolean canGoInDockedStack() {
+ return isResizeable() || inCropWindowsResizeMode();
+ }
+
/**
* Find the activity in the history stack within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
@@ -1070,7 +1085,7 @@
out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
- out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
+ out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
if (mLastNonFullscreenBounds != null) {
out.attribute(
@@ -1136,7 +1151,7 @@
int nextTaskId = INVALID_TASK_ID;
int callingUid = -1;
String callingPackage = "";
- boolean resizeable = false;
+ int resizeMode = RESIZE_MODE_UNRESIZEABLE;
boolean privileged = false;
Rect bounds = null;
@@ -1197,7 +1212,10 @@
} else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
callingPackage = attrValue;
} else if (ATTR_RESIZEABLE.equals(attrName)) {
- resizeable = Boolean.valueOf(attrValue);
+ resizeMode = Boolean.valueOf(attrValue)
+ ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_CROP_WINDOWS;
+ } else if (ATTR_RESIZE_MODE.equals(attrName)) {
+ resizeMode = Integer.valueOf(attrValue);
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.valueOf(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
@@ -1261,7 +1279,7 @@
autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
- taskAffiliationColor, callingUid, callingPackage, resizeable, privileged,
+ taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
realActivitySuspended);
task.updateOverrideConfiguration(bounds);
@@ -1401,7 +1419,7 @@
}
if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- if (!mResizeable) {
+ if (!isResizeable()) {
throw new IllegalArgumentException("Can not position non-resizeable task="
+ this + " in stack=" + inStack);
}
@@ -1447,8 +1465,8 @@
final int stackId = stack.mStackId;
if (stackId == HOME_STACK_ID
|| stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || (stackId == DOCKED_STACK_ID && !mResizeable)) {
- return mResizeable ? stack.mBounds : null;
+ || (stackId == DOCKED_STACK_ID && !isResizeable())) {
+ return isResizeable() ? stack.mBounds : null;
} else if (!StackId.persistTaskBounds(stackId)) {
return stack.mBounds;
}
@@ -1551,12 +1569,12 @@
if (stack != null) {
pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
}
- pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
- pw.print(" mResizeable="); pw.print(mResizeable);
- pw.print(" firstActiveTime="); pw.print(lastActiveTime);
- pw.print(" lastActiveTime="); pw.print(lastActiveTime);
- pw.print(" (inactive for ");
- pw.print((getInactiveDuration()/1000)); pw.println("s)");
+ pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
+ pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
+ pw.print(" isResizeable=" + isResizeable());
+ pw.print(" firstActiveTime=" + lastActiveTime);
+ pw.print(" lastActiveTime=" + lastActiveTime);
+ pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 0029279..c5d38cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -248,10 +248,10 @@
}
public String toString() {
- return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" +
- network + "} lp{" +
- linkProperties + "} nc{" +
- networkCapabilities + "} Score{" + getCurrentScore() + "} " +
+ return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
+ "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
+ "lp{" + linkProperties + "} " +
+ "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} " +
"everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " +
"created{" + created + "} lingering{" + lingering + "} " +
"explicitlySelected{" + networkMisc.explicitlySelected + "} " +
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6648efd..a73a67a 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -153,11 +153,10 @@
// when RNDIS is enabled
public Tethering(Context context, INetworkManagementService nmService,
- INetworkStatsService statsService, Looper looper) {
+ INetworkStatsService statsService) {
mContext = context;
mNMService = nmService;
mStatsService = statsService;
- mLooper = looper;
mPublicSync = new Object();
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 206cc8a..a633996 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -17,6 +17,7 @@
package com.android.server.dreams;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import android.content.ComponentName;
import android.content.Context;
@@ -131,7 +132,7 @@
mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
- mCurrentDream.mCanDoze ? MetricsLogger.DOZING : MetricsLogger.DREAMING);
+ mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -196,7 +197,7 @@
+ ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ ", userId=" + oldDream.mUserId);
MetricsLogger.hidden(mContext,
- oldDream.mCanDoze ? MetricsLogger.DOZING : MetricsLogger.DREAMING);
+ oldDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
MetricsLogger.histogram(mContext,
oldDream.mCanDoze ? "dozing_minutes" : "dreaming_minutes" ,
(int) ((SystemClock.elapsedRealtime() - mDreamStartTime) / (1000L * 60L)));
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e74d636..13e7648 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -48,6 +48,7 @@
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.server.SystemService;
import org.json.JSONArray;
@@ -686,7 +687,7 @@
private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
if (receiver == null) return true; // client not listening
FingerprintUtils.vibrateFingerprintSuccess(getContext());
- MetricsLogger.action(mContext, MetricsLogger.ACTION_FINGERPRINT_ENROLL);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_ENROLL);
try {
receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
return remaining == 0;
@@ -704,7 +705,7 @@
boolean authenticated = fpId != 0;
if (receiver != null) {
try {
- MetricsLogger.action(mContext, MetricsLogger.ACTION_FINGERPRINT_AUTH,
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_AUTH,
authenticated);
if (!authenticated) {
receiver.onAuthenticationFailed(mHalDeviceId);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 573afd6..033a243 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,7 +16,9 @@
package com.android.server.input;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.LocaleList;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
@@ -780,8 +782,10 @@
|| layout.getProductId() != d.getProductId()) {
return;
}
- for (Locale l : layout.getLocales()) {
- if (isCompatibleLocale(systemLocale, l)) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
layouts.add(layout);
break;
}
@@ -799,9 +803,12 @@
final int N = layouts.size();
for (int i = 0; i < N; i++) {
KeyboardLayout layout = layouts.get(i);
- for (Locale l : layout.getLocales()) {
- if (l.getCountry().equals(systemLocale.getCountry())
- && l.getVariant().equals(systemLocale.getVariant())) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ final Locale locale = locales.get(localeIndex);
+ if (locale.getCountry().equals(systemLocale.getCountry())
+ && locale.getVariant().equals(systemLocale.getVariant())) {
return layout.getDescriptor();
}
}
@@ -809,8 +816,11 @@
// Then try an exact match of language and country
for (int i = 0; i < N; i++) {
KeyboardLayout layout = layouts.get(i);
- for (Locale l : layout.getLocales()) {
- if (l.getCountry().equals(systemLocale.getCountry())) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ final Locale locale = locales.get(localeIndex);
+ if (locale.getCountry().equals(systemLocale.getCountry())) {
return layout.getDescriptor();
}
}
@@ -1170,7 +1180,7 @@
0);
String languageTags = a.getString(
com.android.internal.R.styleable.KeyboardLayout_locale);
- Locale[] locales = getLocalesFromLanguageTags(languageTags);
+ LocaleList locales = getLocalesFromLanguageTags(languageTags);
int vid = a.getInt(
com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
int pid = a.getInt(
@@ -1210,16 +1220,12 @@
}
}
- private static Locale[] getLocalesFromLanguageTags(String languageTags) {
+ @NonNull
+ private static LocaleList getLocalesFromLanguageTags(String languageTags) {
if (TextUtils.isEmpty(languageTags)) {
- return new Locale[0];
+ return LocaleList.getEmptyLocaleList();
}
- String[] tags = languageTags.split("\\|");
- Locale[] locales = new Locale[tags.length];
- for (int i = 0; i < tags.length; i++) {
- locales[i] = Locale.forLanguageTag(tags[i]);
- }
- return locales;
+ return LocaleList.forLanguageTags(languageTags.replace('|', ','));
}
/**
@@ -1596,7 +1602,7 @@
final int accessibilityConfig = Settings.Secure.getIntForUser(
mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
0, UserHandle.USER_CURRENT);
- PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
+ PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
nativeReloadPointerIcons(mPtr);
}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
similarity index 96%
rename from services/core/java/com/android/server/location/GpsLocationProvider.java
rename to services/core/java/com/android/server/location/GnssLocationProvider.java
index 88ab2c6..9798e56 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -35,11 +35,12 @@
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
+import android.location.GnssStatus;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
import android.location.GpsMeasurementsEvent;
import android.location.GpsNavigationMessageEvent;
import android.location.IGpsGeofenceHardware;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
import android.location.Location;
@@ -100,9 +101,9 @@
*
* {@hide}
*/
-public class GpsLocationProvider implements LocationProviderInterface {
+public class GnssLocationProvider implements LocationProviderInterface {
- private static final String TAG = "GpsLocationProvider";
+ private static final String TAG = "GnssLocationProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
@@ -366,7 +367,7 @@
private final ILocationManager mILocationManager;
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
- private final GpsStatusListenerHelper mListenerHelper;
+ private final GnssStatusListenerHelper mListenerHelper;
private final GpsMeasurementsProvider mGpsMeasurementsProvider;
private final GpsNavigationMessageProvider mGpsNavigationMessageProvider;
@@ -382,7 +383,7 @@
private final GpsNetInitiatedHandler mNIHandler;
// Wakelocks
- private final static String WAKELOCK_KEY = "GpsLocationProvider";
+ private final static String WAKELOCK_KEY = "GnssLocationProvider";
private final PowerManager.WakeLock mWakeLock;
// Alarms
@@ -405,20 +406,22 @@
private GeofenceHardwareImpl mGeofenceHardwareImpl;
- private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
+ private int mYearOfHardware = 0;
+
+ private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
@Override
- public void addGpsStatusListener(IGpsStatusListener listener) {
- mListenerHelper.addListener(listener);
+ public void registerGnssStatusCallback(IGnssStatusListener callback) {
+ mListenerHelper.addListener(callback);
}
@Override
- public void removeGpsStatusListener(IGpsStatusListener listener) {
- mListenerHelper.removeListener(listener);
+ public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
+ mListenerHelper.removeListener(callback);
}
};
- public IGpsStatusProvider getGpsStatusProvider() {
- return mGpsStatusProvider;
+ public IGnssStatusProvider getGnssStatusProvider() {
+ return mGnssStatusProvider;
}
public IGpsGeofenceHardware getGpsGeofenceProxy() {
@@ -655,7 +658,7 @@
return true;
}
- public GpsLocationProvider(Context context, ILocationManager ilocationManager,
+ public GnssLocationProvider(Context context, ILocationManager ilocationManager,
Looper looper) {
mContext = context;
mNtpTime = NtpTrustedTime.getInstance(context);
@@ -698,7 +701,7 @@
mNetInitiatedListener,
mSuplEsEnabled);
- mListenerHelper = new GpsStatusListenerHelper(mHandler) {
+ mListenerHelper = new GnssStatusListenerHelper(mHandler) {
@Override
protected boolean isAvailableInPlatform() {
return isSupported();
@@ -1554,34 +1557,40 @@
* called from native code to update SV info
*/
private void reportSvStatus() {
- int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
+ int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
+ mConstellationTypes);
mListenerHelper.onSvStatusChanged(
svCount,
- mSvs,
+ mPrnWithFlags,
mSnrs,
mSvElevations,
mSvAzimuths,
- mSvMasks[EPHEMERIS_MASK],
- mSvMasks[ALMANAC_MASK],
- mSvMasks[USED_FOR_FIX_MASK]);
+ mConstellationTypes);
if (VERBOSE) {
- Log.v(TAG, "SV count: " + svCount +
- " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
- " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
- for (int i = 0; i < svCount; i++) {
- Log.v(TAG, "sv: " + mSvs[i] +
+ Log.v(TAG, "SV count: " + svCount);
+ }
+ // Calculate number of sets used in fix.
+ int usedInFixCount = 0;
+ for (int i = 0; i < svCount; i++) {
+ if ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+ ++usedInFixCount;
+ }
+ if (VERBOSE) {
+ Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
" snr: " + mSnrs[i]/10 +
" elev: " + mSvElevations[i] +
" azimuth: " + mSvAzimuths[i] +
- ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
- ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
- ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
+ ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+ ? " " : " E") +
+ ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+ ? " " : " A") +
+ ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+ ? "" : "U"));
}
}
-
// return number of sets used in fix instead of total
- updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
+ updateStatus(mStatus, usedInFixCount);
if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1675,6 +1684,33 @@
}
/**
+ * Called from native code to inform us the hardware information.
+ */
+ private void setGpsYearOfHardware(int yearOfHardware) {
+ if (DEBUG) Log.d(TAG, "setGpsYearOfHardware called with " + yearOfHardware);
+ mYearOfHardware = yearOfHardware;
+ }
+
+ public interface GpsSystemInfoProvider {
+ /**
+ * Returns the year of GPS hardware.
+ */
+ int getGpsYearOfHardware();
+ }
+
+ /**
+ * @hide
+ */
+ public GpsSystemInfoProvider getGpsSystemInfoProvider() {
+ return new GpsSystemInfoProvider() {
+ @Override
+ public int getGpsYearOfHardware() {
+ return mYearOfHardware;
+ }
+ };
+ }
+
+ /**
* called from native code to request XTRA data
*/
private void xtraDownloadRequest() {
@@ -2067,7 +2103,7 @@
}
/**
- * This method is bound to {@link #GpsLocationProvider(Context, ILocationManager, Looper)}.
+ * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
* It is in charge of loading properties and registering for events that will be posted to
* this handler.
*/
@@ -2362,17 +2398,14 @@
}
// for GPS SV statistics
- private static final int MAX_SVS = 32;
- private static final int EPHEMERIS_MASK = 0;
- private static final int ALMANAC_MASK = 1;
- private static final int USED_FOR_FIX_MASK = 2;
+ private static final int MAX_SVS = 512;
// preallocated arrays, to avoid memory allocation in reportStatus()
- private int mSvs[] = new int[MAX_SVS];
+ private int mPrnWithFlags[] = new int[MAX_SVS];
private float mSnrs[] = new float[MAX_SVS];
private float mSvElevations[] = new float[MAX_SVS];
private float mSvAzimuths[] = new float[MAX_SVS];
- private int mSvMasks[] = new int[3];
+ private int mConstellationTypes[] = new int[MAX_SVS];
private int mSvCount;
// preallocated to avoid memory allocation in reportNmea()
private byte[] mNmeaBuffer = new byte[120];
@@ -2392,8 +2425,8 @@
private native void native_delete_aiding_data(int flags);
// returns number of SVs
// mask[0] is ephemeris mask and mask[1] is almanac mask
- private native int native_read_sv_status(int[] svs, float[] snrs,
- float[] elevations, float[] azimuths, int[] masks);
+ private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths, int[] constellationTypes);
private native int native_read_nmea(byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
similarity index 63%
rename from services/core/java/com/android/server/location/GpsStatusListenerHelper.java
rename to services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 53ff6c2..9840c61 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -16,17 +16,17 @@
package com.android.server.location;
-import android.location.IGpsStatusListener;
+import android.location.IGnssStatusListener;
import android.os.Handler;
import android.os.RemoteException;
/**
- * Implementation of a handler for {@link IGpsStatusListener}.
+ * Implementation of a handler for {@link IGnssStatusListener}.
*/
-abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
- protected GpsStatusListenerHelper(Handler handler) {
- super(handler, "GpsStatusListenerHelper");
- setSupported(GpsLocationProvider.isSupported());
+abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
+ protected GnssStatusListenerHelper(Handler handler) {
+ super(handler, "GnssStatusListenerHelper");
+ setSupported(GnssLocationProvider.isSupported());
}
@Override
@@ -38,7 +38,7 @@
protected void unregisterFromService() {}
@Override
- protected ListenerOperation<IGpsStatusListener> getHandlerOperation(int result) {
+ protected ListenerOperation<IGnssStatusListener> getHandlerOperation(int result) {
return null;
}
@@ -47,15 +47,15 @@
if (isNavigating) {
operation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
- listener.onGpsStarted();
+ public void execute(IGnssStatusListener listener) throws RemoteException {
+ listener.onGnssStarted();
}
};
} else {
operation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
- listener.onGpsStopped();
+ public void execute(IGnssStatusListener listener) throws RemoteException {
+ listener.onGnssStopped();
}
};
}
@@ -65,7 +65,7 @@
public void onFirstFix(final int timeToFirstFix) {
Operation operation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
+ public void execute(IGnssStatusListener listener) throws RemoteException {
listener.onFirstFix(timeToFirstFix);
}
};
@@ -74,25 +74,21 @@
public void onSvStatusChanged(
final int svCount,
- final int[] prns,
+ final int[] prnWithFlags,
final float[] snrs,
final float[] elevations,
final float[] azimuths,
- final int ephemerisMask,
- final int almanacMask,
- final int usedInFixMask) {
+ final int[] constellationTypes) {
Operation operation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
+ public void execute(IGnssStatusListener listener) throws RemoteException {
listener.onSvStatusChanged(
svCount,
- prns,
+ prnWithFlags,
snrs,
elevations,
azimuths,
- ephemerisMask,
- almanacMask,
- usedInFixMask);
+ constellationTypes);
}
};
foreach(operation);
@@ -101,12 +97,12 @@
public void onNmeaReceived(final long timestamp, final String nmea) {
Operation operation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
+ public void execute(IGnssStatusListener listener) throws RemoteException {
listener.onNmeaReceived(timestamp, nmea);
}
};
foreach(operation);
}
- private interface Operation extends ListenerOperation<IGpsStatusListener> {}
+ private interface Operation extends ListenerOperation<IGnssStatusListener> {}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 492632c..5c77079 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -652,9 +652,9 @@
case ACTION_USER_REMOVED:
case ACTION_USER_ADDED:
synchronized (mRulesLock) {
- // Remove any policies for given user; both cleaning up after a
+ // Remove any persistable state for the given user; both cleaning up after a
// USER_REMOVED, and one last sanity check during USER_ADDED
- removePoliciesForUserLocked(userId);
+ removeUserStateLocked(userId);
// Update global restrict for new user
updateRulesForGlobalChangeLocked(true);
}
@@ -1666,12 +1666,30 @@
}
/**
- * Remove any policies associated with given {@link UserHandle}, persisting
+ * Remove any persistable state associated with given {@link UserHandle}, persisting
* if any changes are made.
*/
- void removePoliciesForUserLocked(int userId) {
- if (LOGV) Slog.v(TAG, "removePoliciesForUserLocked()");
+ void removeUserStateLocked(int userId) {
+ if (LOGV) Slog.v(TAG, "removeUserStateLocked()");
+ boolean writePolicy = false;
+ // Remove entries from restricted background UID whitelist
+ int[] wlUids = new int[0];
+ for (int i = 0; i < mRestrictBackgroundWhitelistUids.size(); i++) {
+ final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
+ if (UserHandle.getUserId(uid) == userId) {
+ wlUids = appendInt(wlUids, uid);
+ }
+ }
+
+ if (wlUids.length > 0) {
+ for (int uid : wlUids) {
+ removeRestrictBackgroundWhitelistedUidLocked(uid, false);
+ }
+ writePolicy = true;
+ }
+
+ // Remove associated UID policies
int[] uids = new int[0];
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
@@ -1685,6 +1703,10 @@
mUidPolicy.delete(uid);
updateRulesForUidLocked(uid);
}
+ writePolicy = true;
+ }
+
+ if (writePolicy) {
writePolicyLocked();
}
}
@@ -1849,14 +1871,15 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid);
+ removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
}
- private void removeRestrictBackgroundWhitelistedUidLocked(int uid) {
+ private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean writePolicy) {
mRestrictBackgroundWhitelistUids.delete(uid);
- writePolicyLocked();
- // TODO: call other update methods like updateNetworkRulesLocked?
+ if (writePolicy) {
+ writePolicyLocked();
+ }
}
@Override
@@ -2777,7 +2800,7 @@
public void onPackageRemoved(String packageName, int uid) {
if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid);
+ removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
}
@@ -2785,7 +2808,7 @@
public void onPackageRemovedAllUsers(String packageName, int uid) {
if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid);
+ removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 53ba718..479b065 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -66,15 +66,26 @@
*
* <p>Granted to:
* <ul>
- * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
- * so it is not necessarily sufficient to declare this in the manifest.
- * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
* <li>Profile owners.
* </ul>
*/
int USER = 1;
/**
+ * Access level for apps which can access usage summary of device. Device summary includes
+ * usage by apps running in any profiles/users, however this access level does not
+ * allow querying usage of individual apps running in other profiles/users.
+ *
+ * <p>Granted to:
+ * <ul>
+ * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
+ * so it is not necessarily sufficient to declare this in the manifest.
+ * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
+ * </ul>
+ */
+ int DEVICESUMMARY = 2;
+
+ /**
* Access level for apps which can access usage for any app on the device, including apps
* running on other users/profiles.
*
@@ -85,7 +96,7 @@
* <li>The system UID.
* </ul>
*/
- int DEVICE = 2;
+ int DEVICE = 3;
}
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
@@ -107,11 +118,15 @@
return NetworkStatsAccess.Level.DEVICE;
}
+ boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage);
+ if (hasAppOpsPermission || context.checkCallingOrSelfPermission(
+ READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) {
+ return NetworkStatsAccess.Level.DEVICESUMMARY;
+ }
+
boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner
- || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) ==
- PackageManager.PERMISSION_GRANTED) {
+ if (isProfileOwner) {
// Apps with the AppOps permission, profile owners, and apps with the privileged
// permission can access data usage for all apps in this user/profile.
return NetworkStatsAccess.Level.USER;
@@ -131,6 +146,7 @@
case NetworkStatsAccess.Level.DEVICE:
// Device-level access - can access usage for any uid.
return true;
+ case NetworkStatsAccess.Level.DEVICESUMMARY:
case NetworkStatsAccess.Level.USER:
// User-level access - can access usage for any app running in the same user, along
// with some special uids (system, removed, or tethering).
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index b1d6f89..3aeceef 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -484,15 +484,19 @@
public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
long end) {
@NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
- if (accessLevel < NetworkStatsAccess.Level.DEVICE) {
+ if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
throw new SecurityException("Calling package " + mCallingPackage
- + " cannot access device-level network stats");
+ + " cannot access device summary network stats");
}
NetworkStats result = new NetworkStats(end - start, 1);
final long ident = Binder.clearCallingIdentity();
try {
+ // Using access level higher than the one we checked for above.
+ // Reason is that we are combining usage data in a way that is not PII
+ // anymore.
result.combineAllValues(
- internalGetSummaryForNetwork(template, start, end, accessLevel));
+ internalGetSummaryForNetwork(template, start, end,
+ NetworkStatsAccess.Level.DEVICE));
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index cf876ee..5d97afa 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -189,10 +189,6 @@
mInstaller.execute("freecache", uuid, freeStorageSize);
}
- public void moveFiles() throws InstallerException {
- mInstaller.execute("movefiles");
- }
-
/**
* Links the 32 bit native library directory in an application's data
* directory to the real location for backward compatibility. Note that no
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index bce7223..4d66e10 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -70,8 +70,7 @@
}
static boolean canOptimizePackage(PackageParser.Package pkg) {
- return pkg.canHaveOatDir() &&
- ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
+ return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d11da79..05ef8dcd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -76,6 +76,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
+
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
@@ -2174,13 +2175,6 @@
scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- try {
- mInstaller.moveFiles();
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN, "Update commands failed: " + e);
- }
-
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
@@ -8098,9 +8092,15 @@
}
ps.primaryCpuAbiString = adjustedAbi;
- if (ps.pkg != null && ps.pkg.applicationInfo != null) {
+ if (ps.pkg != null && ps.pkg.applicationInfo != null &&
+ !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
+ Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+ + " (requirer="
+ + (requirer == null ? "null" : requirer.pkg.packageName)
+ + ", scannedPackage="
+ + (scannedPackage != null ? scannedPackage.packageName : "null")
+ + ")");
try {
mInstaller.rmdex(ps.codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 901749e..43e4b84 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -863,7 +863,7 @@
if (inPath != null) {
in = new FileInputStream(inPath);
} else {
- in = new SizedInputStream(getInputStream(), sizeBytes);
+ in = new SizedInputStream(getRawInputStream(), sizeBytes);
}
out = session.openWrite(splitName, 0, sizeBytes);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index fc79849..4ff7667 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -25,9 +25,11 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -302,6 +304,12 @@
private final LockPatternUtils mLockPatternUtils;
+ /**
+ * Whether all users should be created ephemeral.
+ */
+ @GuardedBy("mUsersLock")
+ private boolean mForceEphemeralUsers;
+
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
@@ -922,6 +930,7 @@
/** @return a specific user restriction that's in effect currently. */
@Override
public boolean hasUserRestriction(String restrictionKey, int userId) {
+ UserRestrictionsUtils.checkRestriction(restrictionKey);
Bundle restrictions = getEffectiveUserRestrictions(userId);
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
@@ -938,6 +947,7 @@
@Override
public boolean hasBaseUserRestriction(String restrictionKey, int userId) {
checkManageUsersPermission("hasBaseUserRestriction");
+ UserRestrictionsUtils.checkRestriction(restrictionKey);
synchronized (mRestrictionsLock) {
Bundle bundle = mBaseUserRestrictions.get(userId);
return (bundle != null && bundle.getBoolean(restrictionKey, false));
@@ -947,6 +957,7 @@
@Override
public void setUserRestriction(String key, boolean value, int userId) {
checkManageUsersPermission("setUserRestriction");
+ UserRestrictionsUtils.checkRestriction(key);
synchronized (mRestrictionsLock) {
// Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
// a copy.
@@ -1836,23 +1847,25 @@
}
}
- // Add ephemeral flag to guests if required. Also inherit it from parent.
+ userId = getNextAvailableId();
+ Environment.getUserSystemDirectory(userId).mkdirs();
boolean ephemeralGuests = Resources.getSystem()
.getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
- if ((isGuest && ephemeralGuests)
- || (parent != null && parent.info.isEphemeral())) {
- flags |= UserInfo.FLAG_EPHEMERAL;
- }
- userId = getNextAvailableId();
- userInfo = new UserInfo(userId, name, null, flags);
- userInfo.serialNumber = mNextSerialNumber++;
- long now = System.currentTimeMillis();
- userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
- userInfo.partial = true;
- userData = new UserData();
- userData.info = userInfo;
- Environment.getUserSystemDirectory(userInfo.id).mkdirs();
+
synchronized (mUsersLock) {
+ // Add ephemeral flag to guests/users if required. Also inherit it from parent.
+ if ((isGuest && ephemeralGuests) || mForceEphemeralUsers
+ || (parent != null && parent.info.isEphemeral())) {
+ flags |= UserInfo.FLAG_EPHEMERAL;
+ }
+
+ userInfo = new UserInfo(userId, name, null, flags);
+ userInfo.serialNumber = mNextSerialNumber++;
+ long now = System.currentTimeMillis();
+ userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
+ userInfo.partial = true;
+ userData = new UserData();
+ userData.info = userInfo;
mUsers.put(userId, userData);
}
writeUserListLP();
@@ -2914,6 +2927,61 @@
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override
+ public void setForceEphemeralUsers(boolean forceEphemeralUsers) {
+ synchronized (mUsersLock) {
+ mForceEphemeralUsers = forceEphemeralUsers;
+ }
+ }
+
+ @Override
+ public void removeAllUsers() {
+ if (UserHandle.USER_SYSTEM == ActivityManager.getCurrentUser()) {
+ // Remove the non-system users straight away.
+ removeNonSystemUsers();
+ } else {
+ // Switch to the system user first and then remove the other users.
+ BroadcastReceiver userSwitchedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int userId =
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId != UserHandle.USER_SYSTEM) {
+ return;
+ }
+ mContext.unregisterReceiver(this);
+ removeNonSystemUsers();
+ }
+ };
+ IntentFilter userSwitchedFilter = new IntentFilter();
+ userSwitchedFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiver(
+ userSwitchedReceiver, userSwitchedFilter, null, mHandler);
+
+ // Switch to the system user.
+ ActivityManager am =
+ (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ am.switchUser(UserHandle.USER_SYSTEM);
+ }
+ }
+ }
+
+ /* Remove all the users except of the system one. */
+ private void removeNonSystemUsers() {
+ ArrayList<UserInfo> usersToRemove = new ArrayList<>();
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo ui = mUsers.valueAt(i).info;
+ if (ui.id != UserHandle.USER_SYSTEM) {
+ usersToRemove.add(ui);
+ }
+ }
+ }
+ for (UserInfo ui: usersToRemove) {
+ removeUser(ui.id);
+ }
}
private class Shell extends ShellCommand {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 87f505d..7ab071f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -56,7 +56,15 @@
private UserRestrictionsUtils() {
}
- public static final Set<String> USER_RESTRICTIONS = Sets.newArraySet(
+ private static Set<String> newSetWithUniqueCheck(String[] strings) {
+ final Set<String> ret = Sets.newArraySet(strings);
+
+ // Make sure there's no overlap.
+ Preconditions.checkState(ret.size() == strings.length);
+ return ret;
+ }
+
+ public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] {
UserManager.DISALLOW_CONFIG_WIFI,
UserManager.DISALLOW_MODIFY_ACCOUNTS,
UserManager.DISALLOW_INSTALL_APPS,
@@ -94,7 +102,7 @@
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_DATA_ROAMING,
UserManager.DISALLOW_SET_USER_ICON
- );
+ });
/**
* Set of user restriction which we don't want to persist.
@@ -140,6 +148,15 @@
UserManager.DISALLOW_UNMUTE_MICROPHONE
);
+ /**
+ * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
+ */
+ public static void checkRestriction(@NonNull String restriction) {
+ if (!USER_RESTRICTIONS.contains(restriction)) {
+ throw new IllegalArgumentException("Unknown restriction: " + restriction);
+ }
+ }
+
public static void writeRestrictions(@NonNull XmlSerializer serializer,
@Nullable Bundle restrictions, @NonNull String tag) throws IOException {
if (restrictions == null) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 290019c..a1f24f7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -131,6 +131,7 @@
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
private static final int WAKE_LOCK_DOZE = 1 << 6;
private static final int WAKE_LOCK_DRAW = 1 << 7;
+ private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -149,6 +150,7 @@
// Power hints defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_HINT_LOW_POWER = 5;
+ private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
// Power features defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
@@ -444,6 +446,9 @@
// True if we are currently in light device idle mode.
private boolean mLightDeviceIdleMode;
+ // True if we are currently in sustained performance mode.
+ private boolean mSustainedPerformanceMode;
+
// Set of app ids that we will always respect the wake locks for.
int[] mDeviceIdleWhitelist = new int[0];
@@ -452,6 +457,8 @@
private final SparseIntArray mUidState = new SparseIntArray();
+ private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
+
// True if theater mode is enabled
private boolean mTheaterModeEnabled;
@@ -811,6 +818,12 @@
throw new IllegalArgumentException("Wake lock is already dead.");
}
mWakeLocks.add(wakeLock);
+
+ if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+ int numberWakelock = mSustainedPerformanceUid.get(uid);
+ mSustainedPerformanceUid.put(uid, numberWakelock + 1);
+ }
setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
@@ -879,6 +892,17 @@
mRequestWaitForNegativeProximity = true;
}
+
+ if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+ int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
+ if (numberWakelock == 1) {
+ mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
+ } else {
+ mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
+ }
+ }
+
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
removeWakeLockLocked(wakeLock, index);
}
@@ -1501,6 +1525,10 @@
break;
case PowerManager.DRAW_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DRAW;
+ case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
+ if (!wakeLock.mDisabled) {
+ mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
+ }
break;
}
}
@@ -2198,6 +2226,14 @@
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
+
+ if (mSustainedPerformanceMode
+ && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
+ setSustainedPerformanceModeLocked(false);
+ } else if (!mSustainedPerformanceMode
+ && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
+ setSustainedPerformanceModeLocked(true);
+ }
}
/**
@@ -2296,6 +2332,12 @@
}
}
+ private void setSustainedPerformanceModeLocked(boolean mode) {
+ mSustainedPerformanceMode = mode;
+ powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
+ mSustainedPerformanceMode ? 1 : 0);
+ }
+
boolean isDeviceIdleModeInternal() {
synchronized (mLock) {
return mDeviceIdleMode;
@@ -2425,7 +2467,7 @@
void updateUidProcStateInternal(int uid, int procState) {
synchronized (mLock) {
mUidState.put(uid, procState);
- if (mDeviceIdleMode) {
+ if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
updateWakeLockDisabledStatesLocked();
}
}
@@ -2446,7 +2488,9 @@
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.PARTIAL_WAKE_LOCK) {
+ == PowerManager.PARTIAL_WAKE_LOCK
+ || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
@@ -2465,9 +2509,9 @@
}
private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
+ boolean disabled = false;
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
- boolean disabled = false;
if (mDeviceIdleMode) {
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
// If we are in idle mode, we will ignore all partial wake locks that are
@@ -2481,10 +2525,16 @@
disabled = true;
}
}
- if (wakeLock.mDisabled != disabled) {
- wakeLock.mDisabled = disabled;
- return true;
- }
+ } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+ == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
+ && mUidState.get(wakeLock.mOwnerUid,
+ ActivityManager.PROCESS_STATE_CACHED_EMPTY)
+ > ActivityManager.PROCESS_STATE_TOP) {
+ disabled = true;
+ }
+ if (wakeLock.mDisabled != disabled) {
+ wakeLock.mDisabled = disabled;
+ return true;
}
return false;
}
@@ -2695,6 +2745,7 @@
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
+ pw.println(" mSustainedPerformanceMode=" + mSustainedPerformanceMode);
pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2809,6 +2860,14 @@
pw.println();
pw.println("Display Power: " + mDisplayPowerCallbacks);
+ pw.println();
+ pw.println("Sustained Performance UIDs:");
+ for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
+ pw.print(" UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
+ pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
+ }
+
+
wcd = mWirelessChargerDetector;
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 578428b..4e96d71 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -266,7 +266,7 @@
return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
}
- public void addHardwareTvInput(int deviceId, TvInputInfo info) {
+ public void addHardwareInput(int deviceId, TvInputInfo info) {
synchronized (mLock) {
String oldInputId = mHardwareInputIdMap.get(deviceId);
if (oldInputId != null) {
@@ -325,7 +325,7 @@
return false;
}
- public void addHdmiTvInput(int id, TvInputInfo info) {
+ public void addHdmiInput(int id, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
@@ -346,7 +346,7 @@
}
}
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
synchronized (mLock) {
mInputMap.remove(inputId);
int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 62e7fb4..b065e85 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -71,6 +71,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -310,7 +311,7 @@
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
} else {
- inputList.addAll(serviceState.inputList);
+ inputList.addAll(serviceState.hardwareInputList);
}
} else {
try {
@@ -779,15 +780,14 @@
}
}
- private void notifyTvInputInfoChanged(UserState userState, String inputId,
- TvInputInfo inputInfo) {
+ private void setTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
if (DEBUG) {
- Slog.d(TAG, "notifyTvInputInfoChanged(inputId=" + inputId + ", inputInfo=" + inputInfo
- + ")");
+ Slog.d(TAG, "setTvInputInfoLocked(inputInfo=" + inputInfo + ")");
}
+ // TODO: Also update the internal input list.
for (ITvInputManagerCallback callback : userState.callbackSet) {
try {
- callback.onTvInputInfoChanged(inputId, inputInfo);
+ callback.onTvInputInfoChanged(inputInfo);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report changed input info to callback", e);
}
@@ -846,6 +846,36 @@
}
}
+ public void setTvInputInfo(TvInputInfo inputInfo, int userId) {
+ String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
+ String callingPackageName = getCallingPackageName();
+ if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
+ throw new IllegalArgumentException("calling package " + callingPackageName
+ + " is not allowed to change TvInputInfo for " + inputInfoPackageName);
+ }
+
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "setTvInputInfoChanged");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ setTvInputInfoLocked(userState, inputInfo);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private String getCallingPackageName() {
+ final String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ if (packages != null && packages.length > 0) {
+ return packages[0];
+ }
+ return "unknown";
+ }
+
@Override
public int getTvInputState(String inputId, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
@@ -1988,7 +2018,7 @@
private final ServiceConnection connection;
private final ComponentName component;
private final boolean isHardware;
- private final List<TvInputInfo> inputList = new ArrayList<>();
+ private final List<TvInputInfo> hardwareInputList = new ArrayList<>();
private ITvInputService service;
private ServiceCallback callback;
@@ -2185,39 +2215,36 @@
}
}
- private void addTvInputLocked(TvInputInfo inputInfo) {
+ private void addHardwareInputLocked(TvInputInfo inputInfo) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- serviceState.inputList.add(inputInfo);
+ serviceState.hardwareInputList.add(inputInfo);
buildTvInputListLocked(mUserId, null);
}
- @Override
- public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ public void addHardwareInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
+ public void addHdmiInput(int id, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHdmiInput(id, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
ensureHardwarePermission();
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
boolean removed = false;
- for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();
+ for (Iterator<TvInputInfo> it = serviceState.hardwareInputList.iterator();
it.hasNext(); ) {
if (it.next().getId().equals(inputId)) {
it.remove();
@@ -2227,24 +2254,12 @@
}
if (removed) {
buildTvInputListLocked(mUserId, null);
- mTvInputHardwareManager.removeTvInput(inputId);
+ mTvInputHardwareManager.removeHardwareInput(inputId);
} else {
Slog.e(TAG, "failed to remove input " + inputId);
}
}
}
-
- @Override
- public void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
- ensureValidInput(inputInfo);
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "setTvInputInfo(" + inputInfo + ")");
- }
- UserState userState = getOrCreateUserStateLocked(mUserId);
- notifyTvInputInfoChanged(userState, inputId, inputInfo);
- }
- }
}
private final class SessionCallback extends ITvInputSessionCallback.Stub {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 39983dd..c7d7096 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -42,6 +42,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -71,6 +74,7 @@
import android.view.IWindowManager;
import android.view.WindowManager;
+import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -96,7 +100,7 @@
public class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperManagerService";
- static final boolean DEBUG = false;
+ static final boolean DEBUG = true;
final Object mLock = new Object[0];
@@ -106,7 +110,8 @@
*/
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
- static final String WALLPAPER = "wallpaper";
+ static final String WALLPAPER = "wallpaper_orig";
+ static final String WALLPAPER_CROP = "wallpaper";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
@@ -120,6 +125,7 @@
final WallpaperData mWallpaper;
final File mWallpaperDir;
final File mWallpaperFile;
+ final File mWallpaperCropFile;
final File mWallpaperInfoFile;
public WallpaperObserver(WallpaperData wallpaper) {
@@ -128,6 +134,7 @@
mWallpaperDir = getWallpaperDir(wallpaper.userId);
mWallpaper = wallpaper;
mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+ mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
}
@@ -136,8 +143,10 @@
if (path == null) {
return;
}
+ final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+ final File changedFile = new File(mWallpaperDir, path);
+
synchronized (mLock) {
- File changedFile = new File(mWallpaperDir, path);
if (mWallpaperFile.equals(changedFile)
|| mWallpaperInfoFile.equals(changedFile)) {
// changing the wallpaper means we'll need to back up the new one
@@ -148,22 +157,111 @@
}
if (mWallpaperFile.equals(changedFile)) {
notifyCallbacksLocked(mWallpaper);
- final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
if (mWallpaper.wallpaperComponent == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
|| mWallpaper.imageWallpaperPending) {
if (written) {
+ // The image source has finished writing the source image,
+ // so we now produce the crop rect (in the background), and
+ // only publish the new displayable (sub)image as a result
+ // of that work.
+ generateCrop(mWallpaper);
mWallpaper.imageWallpaperPending = false;
+ if (mWallpaper.setComplete != null) {
+ try {
+ mWallpaper.setComplete.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // if this fails we don't really care; the setting app may just
+ // have crashed and that sort of thing is a fact of life.
+ }
+ }
+ bindWallpaperComponentLocked(mImageWallpaper, true,
+ false, mWallpaper, null);
+ saveSettingsLocked(mWallpaper);
}
- bindWallpaperComponentLocked(mImageWallpaper, true,
- false, mWallpaper, null);
- saveSettingsLocked(mWallpaper);
}
}
}
}
}
+ /**
+ * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
+ * for display.
+ */
+ private void generateCrop(WallpaperData wallpaper) {
+ boolean success = false;
+ boolean needCrop = false;
+
+ // Analyse the source; needed in multiple cases
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+
+ // Legacy case uses an empty crop rect here, so we just preserve the
+ // source image verbatim
+ if (!wallpaper.cropHint.isEmpty()) {
+ // ...clamp the crop rect to the measured bounds...
+ wallpaper.cropHint.right = Math.min(wallpaper.cropHint.right, options.outWidth);
+ wallpaper.cropHint.bottom = Math.min(wallpaper.cropHint.bottom, options.outHeight);
+ // ...and don't bother cropping if what we're left with is identity
+ needCrop = (options.outHeight >= wallpaper.cropHint.height()
+ && options.outWidth >= wallpaper.cropHint.width());
+ }
+
+ if (!needCrop) {
+ // Simple case: the nominal crop is at least as big as the source image,
+ // so we take the whole thing and just copy the image file directly.
+ if (DEBUG) {
+ Slog.v(TAG, "Null crop of new wallpaper; copying");
+ }
+ success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+ if (!success) {
+ wallpaper.cropFile.delete();
+ // TODO: fall back to default wallpaper in this case
+ }
+ } else {
+ // Fancy case: the crop is a subrect of the source
+ FileOutputStream f = null;
+ BufferedOutputStream bos = null;
+ try {
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+ wallpaper.wallpaperFile.getAbsolutePath(), false);
+ Bitmap cropped = decoder.decodeRegion(wallpaper.cropHint, null);
+ decoder.recycle();
+
+ if (cropped == null) {
+ Slog.e(TAG, "Could not decode new wallpaper");
+ } else {
+ f = new FileOutputStream(wallpaper.cropFile);
+ bos = new BufferedOutputStream(f, 32*1024);
+ cropped.compress(Bitmap.CompressFormat.PNG, 90, bos);
+ bos.flush(); // don't rely on the implicit flush-at-close when noting success
+ success = true;
+ }
+ } catch (IOException e) {
+ if (DEBUG) {
+ Slog.e(TAG, "I/O error decoding crop: " + e.getMessage());
+ }
+ } finally {
+ IoUtils.closeQuietly(bos);
+ IoUtils.closeQuietly(f);
+ }
+ }
+
+ if (!success) {
+ Slog.e(TAG, "Unable to apply new wallpaper");
+ wallpaper.cropFile.delete();
+ }
+
+ if (wallpaper.cropFile.exists()) {
+ boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+ if (DEBUG) {
+ Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
+ }
+ }
+ }
+
final Context mContext;
final IWindowManager mIWindowManager;
final IPackageManager mIPackageManager;
@@ -191,7 +289,8 @@
int userId;
- File wallpaperFile;
+ final File wallpaperFile;
+ final File cropFile;
/**
* Client is currently writing a new image wallpaper.
@@ -199,6 +298,11 @@
boolean imageWallpaperPending;
/**
+ * Callback once the set + crop is finished
+ */
+ IWallpaperManagerCallback setComplete;
+
+ /**
* Resource name if using a picture from the wallpaper gallery
*/
String name = "";
@@ -232,11 +336,26 @@
int width = -1;
int height = -1;
+ /**
+ * The crop hint supplied for displaying a subset of the source image
+ */
+ final Rect cropHint = new Rect(0, 0, 0, 0);
+
final Rect padding = new Rect(0, 0, 0, 0);
WallpaperData(int userId) {
this.userId = userId;
wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+ cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ }
+
+ // Only called in single-threaded boot sequence mode
+ boolean ensureCropExists() {
+ // if the crop file is not present, copy over the source image to use verbatim
+ if (!cropFile.exists()) {
+ return FileUtils.copyFile(wallpaperFile, cropFile);
+ }
+ return true;
}
}
@@ -524,6 +643,9 @@
public void systemRunning() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+ if (!wallpaper.ensureCropExists()) {
+ clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+ }
switchWallpaper(wallpaper, null);
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
@@ -602,6 +724,8 @@
onStoppingUser(userId);
File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
wallpaperFile.delete();
+ File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ cropFile.delete();
File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
wallpaperInfoFile.delete();
}
@@ -653,9 +777,9 @@
if (wallpaper == null) {
return;
}
- File f = new File(getWallpaperDir(userId), WALLPAPER);
- if (f.exists()) {
- f.delete();
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -844,11 +968,10 @@
outParams.putInt("height", wallpaper.height);
}
wallpaper.callbacks.register(cb);
- File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
- if (!f.exists()) {
+ if (!wallpaper.cropFile.exists()) {
return null;
}
- return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+ return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
Slog.w(TAG, "Error getting wallpaper", e);
@@ -869,8 +992,8 @@
}
@Override
- public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Bundle extras,
- int which) {
+ public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
+ Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (which == 0) {
@@ -881,6 +1004,17 @@
return null;
}
+ // "null" means the no-op crop, preserving the full input image
+ if (cropHint == null) {
+ cropHint = new Rect(0, 0, 0, 0);
+ } else {
+ if (cropHint.isEmpty()
+ || cropHint.left < 0
+ || cropHint.top < 0) {
+ return null;
+ }
+ }
+
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
int userId = UserHandle.getCallingUserId();
@@ -890,6 +1024,8 @@
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
if (pfd != null) {
wallpaper.imageWallpaperPending = true;
+ wallpaper.setComplete = completion;
+ wallpaper.cropHint.set(cropHint);
}
return pfd;
} finally {
@@ -1196,6 +1332,12 @@
out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
out.attribute(null, "width", Integer.toString(wallpaper.width));
out.attribute(null, "height", Integer.toString(wallpaper.height));
+
+ out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
+ out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
+ out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
+ out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+
if (wallpaper.padding.left != 0) {
out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
}
@@ -1208,6 +1350,7 @@
if (wallpaper.padding.bottom != 0) {
out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
}
+
out.attribute(null, "name", wallpaper.name);
if (wallpaper.wallpaperComponent != null
&& !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
@@ -1304,6 +1447,10 @@
wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
wallpaper.height = Integer.parseInt(parser
.getAttributeValue(null, "height"));
+ wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+ wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+ wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+ wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
@@ -1322,6 +1469,7 @@
if (DEBUG) {
Slog.v(TAG, "mWidth:" + wallpaper.width);
Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Slog.v(TAG, "mName:" + wallpaper.name);
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
@@ -1348,6 +1496,7 @@
if (!success) {
wallpaper.width = -1;
wallpaper.height = -1;
+ wallpaper.cropHint.set(0, 0, 0, 0);
wallpaper.padding.set(0, 0, 0, 0);
wallpaper.name = "";
} else {
@@ -1368,6 +1517,11 @@
if (wallpaper.height < baseSize) {
wallpaper.height = baseSize;
}
+ // and crop, if not previously specified
+ if (wallpaper.cropHint.width() <= 0
+ || wallpaper.cropHint.height() <= 0) {
+ wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
+ }
}
private int getMaximumSizeDimension() {
@@ -1431,6 +1585,7 @@
}
}
+ // Restore the named resource bitmap to both source + crop files
boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
String resName = wallpaper.name.substring(4);
@@ -1456,6 +1611,7 @@
int resId = -1;
InputStream res = null;
FileOutputStream fos = null;
+ FileOutputStream cos = null;
try {
Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
Resources r = c.getResources();
@@ -1469,13 +1625,16 @@
res = r.openRawResource(resId);
if (wallpaper.wallpaperFile.exists()) {
wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
}
fos = new FileOutputStream(wallpaper.wallpaperFile);
+ cos = new FileOutputStream(wallpaper.cropFile);
byte[] buffer = new byte[32768];
int amt;
while ((amt=res.read(buffer)) > 0) {
fos.write(buffer, 0, amt);
+ cos.write(buffer, 0, amt);
}
// mWallpaperObserver will notice the close and send the change broadcast
@@ -1491,8 +1650,12 @@
IoUtils.closeQuietly(res);
if (fos != null) {
FileUtils.sync(fos);
- IoUtils.closeQuietly(fos);
}
+ if (cos != null) {
+ FileUtils.sync(cos);
+ }
+ IoUtils.closeQuietly(fos);
+ IoUtils.closeQuietly(cos);
}
}
}
@@ -1520,6 +1683,7 @@
pw.print(wallpaper.width);
pw.print(" mHeight=");
pw.println(wallpaper.height);
+ pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
pw.print(" mPadding="); pw.println(wallpaper.padding);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 552af03..43a17c9 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -134,7 +134,7 @@
/** Fraction of animation at which the recents thumbnail becomes completely transparent */
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
- private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+ static final int DEFAULT_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2732821..c0d34e8 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -125,9 +125,6 @@
boolean mLaunchTaskBehind;
boolean mEnteringAnimation;
- // True if the windows associated with this token should be cropped to their stack bounds.
- boolean mCropWindowsToStack;
-
boolean mAlwaysFocusable;
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
new file mode 100644
index 0000000..5f97478
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Enables animating bounds of objects.
+ *
+ * In multi-window world bounds of both stack and tasks can change. When we need these bounds to
+ * change smoothly and not require the app to relaunch (e.g. because it handles resizes and
+ * relaunching it would cause poorer experience), these class provides a way to directly animate
+ * the bounds of the resized object.
+ *
+ * The object that is resized needs to implement {@link AnimateBoundsUser} interface.
+ */
+public class BoundsAnimationController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM;
+
+ // Only acccessed on UI thread.
+ private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
+
+ private final class BoundsAnimator extends ValueAnimator
+ implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+ private final AnimateBoundsUser mTarget;
+ private final Rect mFrom;
+ private final Rect mTo;
+ private final Rect mTmpRect;
+
+ BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) {
+ super();
+ mTarget = target;
+ mFrom = from;
+ mTo = to;
+ mTmpRect = new Rect();
+ addUpdateListener(this);
+ addListener(this);
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float value = (Float) animation.getAnimatedValue();
+ final float remains = 1 - value;
+ mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value);
+ mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value);
+ mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value);
+ mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value);
+ if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds="
+ + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value
+ + ", remains=" + remains);
+ if (!mTarget.setSize(mTmpRect)) {
+ // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
+ // any further animation.
+ animation.cancel();
+ }
+ }
+
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishAnimation();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ finishAnimation();
+ }
+
+ private void finishAnimation() {
+ mTarget.finishBoundsAnimation();
+ removeListener(this);
+ removeUpdateListener(this);
+ mRunningAnimations.remove(mTarget);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ }
+
+ public interface AnimateBoundsUser {
+ /**
+ * Asks the target to directly (without any intermediate steps, like scheduling animation)
+ * resize its bounds.
+ *
+ * @return Whether the target still wants to be animated and successfully finished the
+ * operation. If it returns false, the animation will immediately be cancelled. The target
+ * should return false when something abnormal happened, e.g. it was completely removed
+ * from the hierarchy and is not valid anymore.
+ */
+ boolean setSize(Rect bounds);
+
+ /**
+ * Callback for the target to inform it that the animation is finished, so it can do some
+ * necessary cleanup.
+ */
+ void finishBoundsAnimation();
+ }
+
+ void animateBounds(AnimateBoundsUser target, Rect from, Rect to) {
+ final BoundsAnimator existing = mRunningAnimations.get(target);
+ if (existing != null) {
+ existing.cancel();
+ }
+ BoundsAnimator animator = new BoundsAnimator(target, from, to);
+ mRunningAnimations.put(target, animator);
+ animator.setFloatValues(0f, 1f);
+ animator.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ animator.setInterpolator(new LinearInterpolator());
+ animator.start();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d9667a1..c542ff6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -19,8 +19,11 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -32,6 +35,7 @@
import static android.view.WindowManager.DOCKED_TOP;
import android.app.ActivityManager.StackId;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.EventLog;
@@ -39,12 +43,14 @@
import android.view.DisplayInfo;
import android.view.Surface;
+import com.android.internal.R;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
import java.util.ArrayList;
class Task implements DimLayer.DimLayerUser {
+ static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
// Return value from {@link setBounds} indicating no change was made to the Task bounds.
static final int BOUNDS_CHANGE_NONE = 0;
// Return value from {@link setBounds} indicating the position of the Task bounds changed.
@@ -84,8 +90,8 @@
// For handling display rotations.
private Rect mTmpRect2 = new Rect();
- // Whether the task is resizeable
- private boolean mResizeable;
+ // Resize mode of the task. See {@link ActivityInfo#resizeMode}
+ private int mResizeMode;
// Whether we need to show toast about the app being non-resizeable when it becomes visible.
// This flag is set when a non-resizeable task is docked (or side-by-side). It's cleared
@@ -95,6 +101,8 @@
// Whether the task is currently being drag-resized
private boolean mDragResizing;
+ private boolean mHomeTask;
+
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
Configuration config) {
mTaskId = taskId;
@@ -125,38 +133,54 @@
mShowNonResizeableDockToast = false;
+ if (isResizeable()) {
+ Slog.wtf(TAG,
+ "Trying to show non-resizeable toast when task is resizeable task=" + this);
+ return;
+ }
+
+ if (mResizeMode == RESIZE_MODE_UNRESIZEABLE) {
+ final String text =
+ mService.mContext.getString(R.string.dock_non_resizeble_failed_to_dock_text);
+ mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST, 0, 0, text).sendToTarget();
+ return;
+ }
+
final int dockSide = mStack.getDockSide();
+ if (!inCropWindowsResizeMode() || dockSide == DOCKED_INVALID) {
+ return;
+ }
+
int xOffset = 0;
int yOffset = 0;
- if (dockSide != DOCKED_INVALID) {
- mStack.getBounds(mTmpRect);
+ mStack.getBounds(mTmpRect);
- if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
- // The toast was originally placed at the bottom and centered. To place it
- // at the bottom-center of the stack, we offset it horizontally by the diff
- // between the center of the stack bounds vs. the center of the screen.
- displayContent.getLogicalDisplayRect(mTmpRect2);
- xOffset = mTmpRect.centerX() - mTmpRect2.centerX();
- } else if (dockSide == DOCKED_TOP) {
- // The toast was originally placed at the bottom and centered. To place it
- // at the bottom center of the top stack, we offset it vertically by the diff
- // between the bottom of the stack bounds vs. the bottom of the content rect.
- //
- // Note here we use the content rect instead of the display rect, as we want
- // the toast's distance to the dock divider (when it's placed at the top half)
- // to be the same as it's distance to the top of the navigation bar (when it's
- // placed at the bottom).
+ if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
+ // The toast was originally placed at the bottom and centered. To place it at the
+ // bottom-center of the stack, we offset it horizontally by the diff between the center
+ // of the stack bounds vs. the center of the screen.
+ displayContent.getLogicalDisplayRect(mTmpRect2);
+ xOffset = mTmpRect.centerX() - mTmpRect2.centerX();
+ } else if (dockSide == DOCKED_TOP) {
+ // The toast was originally placed at the bottom and centered. To place it at the bottom
+ // center of the top stack, we offset it vertically by the diff between the bottom of
+ // the stack bounds vs. the bottom of the content rect.
+ //
+ // Note here we use the content rect instead of the display rect, as we want the toast's
+ // distance to the dock divider (when it's placed at the top half) to be the same as
+ // it's distance to the top of the navigation bar (when it's placed at the bottom).
- // We don't adjust for DOCKED_BOTTOM case since it's already at the bottom.
- displayContent.getContentRect(mTmpRect2);
- yOffset = mTmpRect2.bottom - mTmpRect.bottom;
- }
- mService.mH.obtainMessage(
- SHOW_NON_RESIZEABLE_DOCK_TOAST, xOffset, yOffset).sendToTarget();
+ // We don't adjust for DOCKED_BOTTOM case since it's already at the bottom.
+ displayContent.getContentRect(mTmpRect2);
+ yOffset = mTmpRect2.bottom - mTmpRect.bottom;
}
+ final String text =
+ mService.mContext.getString(R.string.dock_cropped_windows_text);
+ mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST,
+ xOffset, yOffset, text).sendToTarget();
}
- void addAppToken(int addPos, AppWindowToken wtoken) {
+ void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
final int lastPos = mAppTokens.size();
if (addPos >= lastPos) {
addPos = lastPos;
@@ -171,6 +195,8 @@
mAppTokens.add(addPos, wtoken);
wtoken.mTask = this;
mDeferRemoval = false;
+ mResizeMode = resizeMode;
+ mHomeTask = homeTask;
}
private boolean hasAppTokensAlive() {
@@ -184,11 +210,11 @@
void removeLocked() {
if (hasAppTokensAlive() && mStack.isAnimating()) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: deferring removing taskId=" + mTaskId);
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
mDeferRemoval = true;
return;
}
- if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: removing taskId=" + mTaskId);
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
mDeferRemoval = false;
DisplayContent content = getDisplayContent();
@@ -203,7 +229,7 @@
if (stack == mStack) {
return;
}
- if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: removing taskId=" + mTaskId
+ if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
if (mStack != null) {
@@ -214,7 +240,7 @@
void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) {
if (mStack != null && stack != mStack) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskInStack: removing taskId=" + mTaskId
+ if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
mStack.removeTask(this);
@@ -319,12 +345,21 @@
out.set(mTempInsetBounds);
}
- void setResizeable(boolean resizeable) {
- mResizeable = resizeable;
+ void setResizeable(int resizeMode) {
+ mResizeMode = resizeMode;
}
boolean isResizeable() {
- return mResizeable;
+ return !mHomeTask
+ && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
+ }
+
+ boolean cropWindowsToStackBounds() {
+ return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
+ }
+
+ private boolean inCropWindowsResizeMode() {
+ return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
}
boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
@@ -551,7 +586,7 @@
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
- if (DEBUG_RESIZE) Slog.d(TAG_WM, "resizeWindows: Resizing " + win);
+ if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
}
}
@@ -563,7 +598,7 @@
final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
- if (DEBUG_RESIZE) Slog.d(TAG_WM, "moveWindows: Moving " + win);
+ if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
win.mMovedByResize = true;
}
}
@@ -619,7 +654,7 @@
}
boolean isTwoFingerScrollMode() {
- return isDockedInEffect() && !isResizeable();
+ return inCropWindowsResizeMode() && isDockedInEffect();
}
WindowState getTopVisibleAppMainWindow() {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 2833b35..e6fa837 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.RemoteException;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -47,7 +48,8 @@
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-public class TaskStack implements DimLayer.DimLayerUser {
+public class TaskStack implements DimLayer.DimLayerUser,
+ BoundsAnimationController.AnimateBoundsUser {
// If the stack should be resized to fullscreen.
private static final boolean FULLSCREEN = true;
@@ -72,6 +74,12 @@
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
+ /** Screen content area excluding IM windows, etc. */
+ private final Rect mContentBounds = new Rect();
+
+ /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+ private final Rect mAdjustedBounds = new Rect();
+
/** Whether mBounds is fullscreen */
private boolean mFullscreen = true;
@@ -162,6 +170,85 @@
return mTmpRect.equals(bounds);
}
+ void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+ if (mFullscreen) {
+ return;
+ }
+ // Update bounds of containing tasks.
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ if (task.isTwoFingerScrollMode()) {
+ // If we're scrolling we don't care about your bounds or configs,
+ // they should be null as if we were in fullscreen.
+ task.resizeLocked(null, null, false /* forced */);
+ task.getBounds(mTmpRect2);
+ task.scrollLocked(mTmpRect2);
+ } else if (task.isResizeable()) {
+ task.getBounds(mTmpRect2);
+ mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+ task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
+ }
+ }
+ }
+
+ void adjustForIME(final WindowState imeWin) {
+ final int dockedSide = getDockSide();
+ final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+ final Rect adjustedBounds = mAdjustedBounds;
+ if (imeWin == null || !dockedTopOrBottom) {
+ // If mContentBounds is already empty, it means we're not applying
+ // any adjustments, so nothing to do; otherwise clear any adjustments.
+ if (!mContentBounds.isEmpty()) {
+ mContentBounds.setEmpty();
+ adjustedBounds.set(mBounds);
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ return;
+ }
+
+ final Rect displayContentRect = mTmpRect;
+ final Rect contentBounds = mTmpRect2;
+
+ // Calculate the content bounds excluding the area occupied by IME
+ mDisplayContent.getContentRect(displayContentRect);
+ contentBounds.set(displayContentRect);
+ int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ imeTop += imeWin.getGivenContentInsetsLw().top;
+ if (contentBounds.bottom > imeTop) {
+ contentBounds.bottom = imeTop;
+ }
+
+ // If content bounds not changing, nothing to do.
+ if (mContentBounds.equals(contentBounds)) {
+ return;
+ }
+
+ // Content bounds changed, need to apply adjustments depending on dock sides.
+ mContentBounds.set(contentBounds);
+ adjustedBounds.set(mBounds);
+ final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+ if (dockedSide == DOCKED_TOP) {
+ // If this stack is docked on top, we make it smaller so the bottom stack is not
+ // occluded by IME. We shift its bottom up by the height of the IME (capped by
+ // the display content rect). Note that we don't change the task bounds.
+ adjustedBounds.bottom = Math.max(
+ adjustedBounds.bottom - yOffset, displayContentRect.top);
+ } else {
+ // If this stack is docked on bottom, we shift it up so that it's not occluded by
+ // IME. We try to move it up by the height of the IME window (although the best
+ // we could do is to make the top stack fully collapsed).
+ final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
+ adjustedBounds.top = Math.max(
+ adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+
+ // We also move the member tasks together, taking care not to resize them.
+ // Resizing might cause relaunch, and IME window may not come back after that.
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ }
+
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
@@ -191,6 +278,16 @@
mBounds.set(bounds);
mRotation = rotation;
+
+ // Clear the adjusted content bounds as they're no longer valid.
+ // If IME is still visible, these will be re-applied.
+ // Note that we don't clear mContentBounds here, so that we know the last IME
+ // adjust we applied.
+ // If user starts dragging the dock divider while IME is visible, the new bounds
+ // we received are based on the actual screen location of the divider. It already
+ // accounted for the IME window, so we don't want to adjust again.
+ mAdjustedBounds.set(mBounds);
+
return true;
}
@@ -215,9 +312,14 @@
public void getBounds(Rect out) {
if (useCurrentBounds()) {
- // No need to adjust the output bounds if fullscreen or the docked stack is visible
+ // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
+ // no need to adjust the output bounds if fullscreen or the docked stack is visible
// since it is already what we want to represent to the rest of the system.
- out.set(mBounds);
+ if (!mContentBounds.isEmpty()) {
+ out.set(mAdjustedBounds);
+ } else {
+ out.set(mBounds);
+ }
return;
}
@@ -587,6 +689,7 @@
outBounds.top = dockedBounds.bottom + dockDividerWidth;
}
}
+ DockedDividerUtils.sanitizeStackBounds(outBounds);
}
/** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
@@ -803,4 +906,32 @@
}
return false;
}
+
+ @Override // AnimatesBounds
+ public boolean setSize(Rect bounds) {
+ synchronized (mService.mWindowMap) {
+ if (mDisplayContent == null) {
+ return false;
+ }
+ }
+ try {
+ mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
+ } catch (RemoteException e) {
+ }
+ return true;
+ }
+
+ @Override // AnimatesBounds
+ public void finishBoundsAnimation() {
+ synchronized (mService.mWindowMap) {
+ if (mTasks.isEmpty()) {
+ return;
+ }
+ final Task task = mTasks.get(mTasks.size() - 1);
+ if (task != null) {
+ task.setDragResizing(false);
+ mService.requestTraversal();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 0979cd3..66aa863 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,10 +35,10 @@
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG = false;
- static final boolean DEBUG_ADD_REMOVE = false;
+ static final boolean DEBUG_ADD_REMOVE = true;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
- static final boolean DEBUG_ANIM = false;
+ static final boolean DEBUG_ANIM = true;
static final boolean DEBUG_KEYGUARD = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93a1015..849fc33 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -114,7 +114,6 @@
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
import android.widget.Toast;
-
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
@@ -157,9 +156,11 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -218,8 +219,8 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
@@ -490,6 +491,8 @@
private final SparseIntArray mTmpTaskIds = new SparseIntArray();
+ boolean mForceResizableTasks = false;
+
int getDragLayerLocked() {
return mPolicy.windowTypeToLayerLw(LayoutParams.TYPE_DRAG) * TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
@@ -643,6 +646,9 @@
final WindowAnimator mAnimator;
+ private final BoundsAnimationController mBoundsAnimationController =
+ new BoundsAnimationController();
+
SparseArray<Task> mTaskIdToTask = new SparseArray<>();
/** All of the TaskStacks in the window manager, unordered. For an ordered list call
@@ -1887,6 +1893,12 @@
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_QS_DIALOG) {
+ if (token.windowType != TYPE_QS_DIALOG) {
+ Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
} else if (token.appWindowToken != null) {
Slog.w(TAG_WM, "Non-null appWindowToken for system window of type=" + type);
// It is not valid to use an app token with other system types; we will
@@ -2848,11 +2860,12 @@
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
win.prepareWindowToDisplayDuringRelayout(outConfig);
}
- if ((attrChanges& LayoutParams.FORMAT_CHANGED) != 0) {
- // If the format can be changed in place yaay!
- // If not, fall back to a surface re-build
+ if ((attrChanges & LayoutParams.FORMAT_CHANGED) != 0) {
+ // If the format can't be changed in place, preserve the old surface until the app draws
+ // on the new one. This prevents blinking when we change elevation of freeform and
+ // pinned windows.
if (!winAnimator.tryChangeFormatInPlaceLocked()) {
- winAnimator.destroySurfaceLocked();
+ winAnimator.preserveSurfaceLocked();
result |= RELAYOUT_RES_SURFACE_CHANGED
| WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
}
@@ -3208,8 +3221,8 @@
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds, Configuration config, boolean cropWindowsToStack,
- boolean alwaysFocusable) {
+ Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,
+ boolean homeTask) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3243,7 +3256,6 @@
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
- atoken.mCropWindowsToStack = cropWindowsToStack;
atoken.mAlwaysFocusable = alwaysFocusable;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3252,7 +3264,7 @@
if (task == null) {
task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
}
- task.addAppToken(addPos, atoken);
+ task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
mTokenMap.put(token.asBinder(), atoken);
@@ -3263,8 +3275,8 @@
}
@Override
- public void setAppTask(
- IBinder token, int taskId, int stackId, Rect taskBounds, Configuration config) {
+ public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
+ Configuration config, int taskResizeMode, boolean homeTask) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3284,7 +3296,7 @@
newTask = createTaskLocked(
taskId, stackId, oldTask.mUserId, atoken, taskBounds, config);
}
- newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
+ newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken, taskResizeMode, homeTask);
}
}
@@ -8070,8 +8082,29 @@
}
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mWindowMap) {
- getDefaultDisplayContentLocked().getDockedDividerController()
- .reevaluateVisibility(false);
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+
+ displayContent.getDockedDividerController().reevaluateVisibility(false);
+
+ final WindowState imeWin = mInputMethodWindow;
+ final TaskStack focusedStack =
+ mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
+ && focusedStack.getDockSide() == DOCKED_BOTTOM){
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack.isVisibleLocked()) {
+ stack.adjustForIME(imeWin);
+ }
+ }
+ } else {
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ stack.adjustForIME(null);
+ }
+ }
}
}
break;
@@ -8085,16 +8118,16 @@
break;
case RESIZE_STACK: {
try {
- mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1);
+ mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false,
+ false);
} catch (RemoteException e) {
// This will not happen since we are in the same process.
}
}
break;
case SHOW_NON_RESIZEABLE_DOCK_TOAST: {
- final Toast toast = Toast.makeText(mContext,
- mContext.getString(R.string.dock_non_resizeble_text),
- Toast.LENGTH_LONG);
+ final Toast toast = Toast.makeText(
+ mContext, (String) msg.obj, Toast.LENGTH_LONG);
final int gravity = toast.getGravity();
final int xOffset = toast.getXOffset() + msg.arg1;
final int yOffset = toast.getYOffset() + msg.arg2;
@@ -10273,12 +10306,43 @@
}
}
- public void setTaskResizeable(int taskId, boolean resizeable) {
+ public void animateResizePinnedStack(final Rect bounds) {
synchronized (mWindowMap) {
- Task task = mTaskIdToTask.get(taskId);
- if (task != null) {
- task.setResizeable(resizeable);
+ final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+ if (stack == null) {
+ Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
+ return;
}
+ final ArrayList<Task> tasks = stack.getTasks();
+ if (tasks.isEmpty()) {
+ Slog.w(TAG, "animateResizePinnedStack: pinned stack doesn't have any tasks.");
+ return;
+ }
+ final Task task = tasks.get(tasks.size() - 1);
+ task.setDragResizing(true);
+ final Rect originalBounds = new Rect();
+ stack.getBounds(originalBounds);
+ UiThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mBoundsAnimationController.animateBounds(stack, originalBounds, bounds);
+ }
+ });
+ }
+ }
+
+ public void setTaskResizeable(int taskId, int resizeMode) {
+ synchronized (mWindowMap) {
+ final Task task = mTaskIdToTask.get(taskId);
+ if (task != null) {
+ task.setResizeable(resizeMode);
+ }
+ }
+ }
+
+ public void setForceResizableTasks(boolean forceResizableTasks) {
+ synchronized (mWindowMap) {
+ mForceResizableTasks = forceResizableTasks;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e8de90c..10a2a6c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -57,6 +57,7 @@
import java.util.ArrayList;
import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -750,15 +751,16 @@
Math.min(mStableFrame.bottom, frame.bottom));
}
- mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
- Math.max(mOverscanFrame.top - frame.top, 0),
- Math.max(frame.right - mOverscanFrame.right, 0),
- Math.max(frame.bottom - mOverscanFrame.bottom, 0));
-
-
+ if (!inFreeformWorkspace()) {
+ // Freeform windows can be positioned outside of the display frame, but that is not a
+ // reason to provide them with overscan insets.
+ mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+ Math.max(mOverscanFrame.top - frame.top, 0),
+ Math.max(frame.right - mOverscanFrame.right, 0),
+ Math.max(frame.bottom - mOverscanFrame.bottom, 0));
+ }
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-
// For the docked divider, we calculate the stable insets like a full-screen window
// so it can use it to calculate the snap positions.
mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
@@ -1000,11 +1002,12 @@
* @param bounds The rect which gets the bounds.
*/
void getVisibleBounds(Rect bounds) {
- boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
+ final Task task = getTask();
+ boolean intersectWithStackBounds = task != null && task.cropWindowsToStackBounds();
bounds.setEmpty();
mTmpRect.setEmpty();
if (intersectWithStackBounds) {
- final TaskStack stack = getStack();
+ final TaskStack stack = task.mStack;
if (stack != null) {
stack.getDimBounds(mTmpRect);
} else {
@@ -1930,11 +1933,12 @@
}
void cropRegionToStackBoundsIfNeeded(Region region) {
- if (mAppToken == null || !mAppToken.mCropWindowsToStack) {
+ final Task task = getTask();
+ if (task == null || !task.cropWindowsToStackBounds()) {
return;
}
- final TaskStack stack = getStack();
+ final TaskStack stack = task.mStack;
if (stack == null) {
return;
}
@@ -2051,17 +2055,29 @@
// until the window to small size, otherwise the multithread renderer will shift last
// one or more frame to wrong offset. So here we send fullscreen backdrop if either
// isDragResizing() or isDragResizeChanged() is true.
+ boolean resizing = isDragResizing() || isDragResizeChanged();
+ if (StackId.useWindowFrameForBackdrop(getStackId()) || !resizing) {
+ return frame;
+ }
DisplayInfo displayInfo = getDisplayInfo();
mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
- boolean resizing = isDragResizing() || isDragResizeChanged();
- return (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
+ return mTmpRect;
+ }
+
+ private int getStackId() {
+ final TaskStack stack = getStack();
+ if (stack == null) {
+ return INVALID_STACK_ID;
+ }
+ return stack.mStackId;
}
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Configuration newConfig) throws RemoteException {
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
- reportDraw, newConfig, getBackdropFrame(frame));
+ reportDraw, newConfig, getBackdropFrame(frame),
+ isDragResizeChanged() /* forceRelayout */);
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -2225,7 +2241,8 @@
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
- pw.print(" isReadyForDisplay()="); pw.println(isReadyForDisplay());
+ pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
+ pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
if (dumpAll) {
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
pw.print(" last="); mLastFrame.printShortString(pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index cffcc5d..d21a3b4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -567,6 +567,10 @@
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
+ if (w.hasSavedSurface()) {
+ Slog.i(TAG, "***** createSurface: " + this + ": called when we had a saved surface");
+ }
+
if (mSurfaceController == null) {
if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
"createSurface " + this + ": mDrawState=DRAW_PENDING");
@@ -1167,9 +1171,8 @@
}
private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
- final AppWindowToken appToken = w.mAppToken;
final Task task = w.getTask();
- if (task == null || !appToken.mCropWindowsToStack) {
+ if (task == null || !task.cropWindowsToStackBounds()) {
return;
}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 98d8d08..d1b8648 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -22,7 +22,7 @@
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
$(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
$(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
similarity index 79%
rename from services/core/jni/com_android_server_location_GpsLocationProvider.cpp
rename to services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b8d4196..0c85a15 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#define LOG_TAG "GpsLocationProvider"
+#define LOG_TAG "GnssLocationProvider"
#define LOG_NDEBUG 0
#include "JNIHelp.h"
#include "jni.h"
#include "hardware/hardware.h"
-#include "hardware/gps.h"
+#include "hardware/gps_internal.h"
#include "hardware_legacy/power.h"
#include "utils/Log.h"
#include "utils/misc.h"
@@ -42,6 +42,7 @@
static jmethodID method_reportAGpsStatus;
static jmethodID method_reportNmea;
static jmethodID method_setEngineCapabilities;
+static jmethodID method_setGpsYearOfHardware;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
static jmethodID method_requestRefLocation;
@@ -67,8 +68,14 @@
static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
+#define MAX_SATELLITE_COUNT 512
+#define MAX_GPS_SATELLITE_COUNT 512
+
+#define PRN_SHIFT_WIDTH 3
+
// temporary storage for GPS callbacks
-static GpsSvStatus sGpsSvStatus;
+static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static size_t sGnssSvListSize;
static const char* sNmeaString;
static int sNmeaStringLength;
@@ -105,7 +112,57 @@
static void sv_status_callback(GpsSvStatus* sv_status)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
- memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
+ size_t status_size = sv_status->size;
+ // Some drive doesn't set the size field correctly. Assume GpsSvStatus_v1 if
+ // it doesn't provide a valid size.
+ if (status_size == 0) {
+ status_size = sizeof(GpsSvStatus_v1);
+ }
+ if (status_size == sizeof(GpsSvStatus)) {
+ sGnssSvListSize = sv_status->gnss_sv_list_size;
+ // Cramp the list size
+ if (sGnssSvListSize > MAX_SATELLITE_COUNT) {
+ sGnssSvListSize = MAX_SATELLITE_COUNT;
+ }
+ // Copy GNSS SV info into sGnssSvList, if any.
+ if (sGnssSvListSize > 0 && sv_status->gnss_sv_list) {
+ memcpy(sGnssSvList, sv_status->gnss_sv_list, sizeof(GnssSvInfo) * sGnssSvListSize);
+ }
+ } else if (status_size == sizeof(GpsSvStatus_v1)) {
+ sGnssSvListSize = sv_status->num_svs;
+ // Cramp the list size
+ if (sGnssSvListSize > MAX_GPS_SATELLITE_COUNT) {
+ sGnssSvListSize = MAX_GPS_SATELLITE_COUNT;
+ }
+ uint32_t ephemeris_mask = sv_status->ephemeris_mask;
+ uint32_t almanac_mask = sv_status->almanac_mask;
+ uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
+ for (size_t i = 0; i < sGnssSvListSize; i++) {
+ GnssSvInfo& info = sGnssSvList[i];
+ info.constellation = GNSS_CONSTELLATION_GPS;
+ info.prn = sv_status->sv_list[i].prn;
+ info.snr = sv_status->sv_list[i].snr;
+ info.elevation = sv_status->sv_list[i].elevation;
+ info.azimuth = sv_status->sv_list[i].azimuth;
+ info.flags = GNSS_SV_FLAGS_NONE;
+ if (info.prn > 0 && info.prn <= 32) {
+ int32_t this_prn_mask = (1 << (info.prn - 1));
+ if ((ephemeris_mask & this_prn_mask) != 0) {
+ info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
+ }
+ if ((almanac_mask & this_prn_mask) != 0) {
+ info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
+ }
+ if ((used_in_fix_mask & this_prn_mask) != 0) {
+ info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
+ }
+ }
+ }
+ } else {
+ sGnssSvListSize = 0;
+ ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+ return;
+ }
env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
@@ -121,6 +178,14 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
+static void set_system_info_callback(const GpsSystemInfo* info) {
+ ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGpsYearOfHardware,
+ info->year_of_hw);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
static void set_capabilities_callback(uint32_t capabilities)
{
ALOGD("set_capabilities_callback: %du\n", capabilities);
@@ -162,6 +227,7 @@
release_wakelock_callback,
create_thread_callback,
request_utc_time_callback,
+ set_system_info_callback,
};
static void xtra_download_request_callback()
@@ -213,7 +279,7 @@
bool isSupported = false;
size_t status_size = agps_status->size;
- if (status_size == sizeof(AGpsStatus_v3)) {
+ if (status_size == sizeof(AGpsStatus)) {
ALOGV("AGpsStatus is V3: %zd", status_size);
switch (agps_status->addr.ss_family)
{
@@ -439,7 +505,7 @@
create_thread_callback,
};
-static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
@@ -449,6 +515,7 @@
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+ method_setGpsYearOfHardware = env->GetMethodID(clazz, "setGpsYearOfHardware", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
@@ -509,13 +576,13 @@
}
}
-static jboolean android_location_GpsLocationProvider_is_supported(
+static jboolean android_location_GnssLocationProvider_is_supported(
JNIEnv* /* env */, jclass /* clazz */)
{
return (sGpsInterface != NULL) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_is_agps_ril_supported(
+static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
JNIEnv* /* env */, jclass /* clazz */)
{
return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
@@ -527,7 +594,7 @@
return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
+static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj)
{
// this must be set before calling into the HAL library
if (!mCallbacksObj)
@@ -553,13 +620,13 @@
return JNI_TRUE;
}
-static void android_location_GpsLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
+static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
{
if (sGpsInterface)
sGpsInterface->cleanup();
}
-static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
jint preferred_time)
{
@@ -575,7 +642,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
+static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
{
if (sGpsInterface) {
if (sGpsInterface->start() == 0) {
@@ -588,7 +655,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
+static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
{
if (sGpsInterface) {
if (sGpsInterface->stop() == 0) {
@@ -601,7 +668,7 @@
return JNI_FALSE;
}
-static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
jobject /* obj */,
jint flags)
{
@@ -609,38 +676,36 @@
sGpsInterface->delete_aiding_data(flags);
}
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
- jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
- jintArray maskArray)
+static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
+ jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+ jfloatArray azumArray, jintArray constellationTypeArray)
{
// this should only be called from within a call to reportSvStatus
-
- jint* prns = env->GetIntArrayElements(prnArray, 0);
+ jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
- jint* mask = env->GetIntArrayElements(maskArray, 0);
+ jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
- int num_svs = sGpsSvStatus.num_svs;
- for (int i = 0; i < num_svs; i++) {
- prns[i] = sGpsSvStatus.sv_list[i].prn;
- snrs[i] = sGpsSvStatus.sv_list[i].snr;
- elev[i] = sGpsSvStatus.sv_list[i].elevation;
- azim[i] = sGpsSvStatus.sv_list[i].azimuth;
+ // GNSS SV info.
+ for (size_t i = 0; i < sGnssSvListSize; ++i) {
+ const GnssSvInfo& info = sGnssSvList[i];
+ constellationTypes[i] = info.constellation;
+ prnWithFlags[i] = (info.prn << PRN_SHIFT_WIDTH) | info.flags;
+ snrs[i] = info.snr;
+ elev[i] = info.elevation;
+ azim[i] = info.azimuth;
}
- mask[0] = sGpsSvStatus.ephemeris_mask;
- mask[1] = sGpsSvStatus.almanac_mask;
- mask[2] = sGpsSvStatus.used_in_fix_mask;
- env->ReleaseIntArrayElements(prnArray, prns, 0);
+ env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
env->ReleaseFloatArrayElements(snrArray, snrs, 0);
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azumArray, azim, 0);
- env->ReleaseIntArrayElements(maskArray, mask, 0);
- return (jint) num_svs;
+ env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
+ return (jint) sGnssSvListSize;
}
-static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
+static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
{
AGpsRefLocation location;
@@ -667,7 +732,7 @@
sAGpsRilInterface->set_ref_location(&location, sizeof(location));
}
-static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
+static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env,
jobject /* obj */, jbyteArray ni_msg, jint size)
{
size_t sz;
@@ -684,7 +749,7 @@
env->ReleaseByteArrayElements(ni_msg,b,0);
}
-static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
jint type, jstring setid_string)
{
if (!sAGpsRilInterface) {
@@ -697,7 +762,7 @@
env->ReleaseStringUTFChars(setid_string, setid);
}
-static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
+static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
jbyteArray nmeaArray, jint buffer_size)
{
// this should only be called from within a call to reportNmea
@@ -710,27 +775,27 @@
return (jint) length;
}
-static void android_location_GpsLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
+static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
jlong time, jlong timeReference, jint uncertainty)
{
if (sGpsInterface)
sGpsInterface->inject_time(time, timeReference, uncertainty);
}
-static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
{
if (sGpsInterface)
sGpsInterface->inject_location(latitude, longitude, accuracy);
}
-static jboolean android_location_GpsLocationProvider_supports_xtra(
+static jboolean android_location_GnssLocationProvider_supports_xtra(
JNIEnv* /* env */, jobject /* obj */)
{
return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
}
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
jbyteArray data, jint length)
{
if (!sGpsXtraInterface) {
@@ -743,7 +808,7 @@
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
-static void android_location_GpsLocationProvider_agps_data_conn_open(
+static void android_location_GnssLocationProvider_agps_data_conn_open(
JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
{
if (!sAGpsInterface) {
@@ -758,7 +823,7 @@
const char *apnStr = env->GetStringUTFChars(apn, NULL);
size_t interface_size = sAGpsInterface->size;
- if (interface_size == sizeof(AGpsInterface_v2)) {
+ if (interface_size == sizeof(AGpsInterface)) {
sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
} else if (interface_size == sizeof(AGpsInterface_v1)) {
sAGpsInterface->data_conn_open(apnStr);
@@ -769,7 +834,7 @@
env->ReleaseStringUTFChars(apn, apnStr);
}
-static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
jobject /* obj */)
{
if (!sAGpsInterface) {
@@ -779,7 +844,7 @@
sAGpsInterface->data_conn_closed();
}
-static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
jobject /* obj */)
{
if (!sAGpsInterface) {
@@ -789,7 +854,7 @@
sAGpsInterface->data_conn_failed();
}
-static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
jint type, jstring hostname, jint port)
{
if (!sAGpsInterface) {
@@ -801,7 +866,7 @@
env->ReleaseStringUTFChars(hostname, c_hostname);
}
-static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* /* env */,
+static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
jobject /* obj */, jint notifId, jint response)
{
if (!sGpsNiInterface) {
@@ -812,7 +877,7 @@
sGpsNiInterface->respond(notifId, response);
}
-static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env,
+static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
jobject /* obj */) {
jstring result = NULL;
if (sGpsDebugInterface) {
@@ -826,7 +891,7 @@
return result;
}
-static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
+static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
{
@@ -849,13 +914,13 @@
}
}
-static jboolean android_location_GpsLocationProvider_is_geofence_supported(
+static jboolean android_location_GnssLocationProvider_is_geofence_supported(
JNIEnv* /* env */, jobject /* obj */)
{
return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
jint last_transition, jint monitor_transition, jint notification_responsiveness,
jint unknown_timer) {
@@ -870,7 +935,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofence_id) {
if (sGpsGeofencingInterface != NULL) {
sGpsGeofencingInterface->remove_geofence_area(geofence_id);
@@ -881,7 +946,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofence_id) {
if (sGpsGeofencingInterface != NULL) {
sGpsGeofencingInterface->pause_geofence(geofence_id);
@@ -892,7 +957,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* /* env */,
+static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofence_id, jint monitor_transition) {
if (sGpsGeofencingInterface != NULL) {
sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
@@ -903,10 +968,12 @@
return JNI_FALSE;
}
-static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
const char* doubleSignature = "(D)V";
const char* longSignature = "(J)V";
+ GpsClock* clock = reinterpret_cast<GpsClock*>(data);
+
jclass gpsClockClass = env->FindClass("android/location/GpsClock");
jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
@@ -958,11 +1025,23 @@
env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
}
+ if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
+ if (size == sizeof(GpsClock)) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsClockClass,
+ "setTimeOfLastHwClockDiscontinuityInNs",
+ longSignature);
+ env->CallVoidMethod(gpsClockObject,
+ setterMethod,
+ clock->time_of_last_hw_clock_discontinuity_ns);
+ }
+ }
+
env->DeleteLocalRef(gpsClockClass);
return gpsClockObject;
}
-static jobject translate_gps_measurement(JNIEnv* env, GpsMeasurement* measurement) {
+static jobject translate_gps_measurement(JNIEnv* env, void* data, size_t size) {
const char* byteSignature = "(B)V";
const char* shortSignature = "(S)V";
const char* intSignature = "(I)V";
@@ -972,6 +1051,7 @@
jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
+ GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
GpsMeasurementFlags flags = measurement->flags;
@@ -1205,12 +1285,38 @@
usedInFixSetterMethod,
(flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+ if (size == sizeof(GpsMeasurement)) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsMeasurementClass,
+ "setPseudorangeRateCarrierInMetersPerSec",
+ doubleSignature);
+ env->CallVoidMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->pseudorange_rate_carrier_mps);
+
+ setterMethod =
+ env->GetMethodID(gpsMeasurementClass,
+ "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
+ doubleSignature);
+ env->CallVoidMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->pseudorange_rate_carrier_uncertainty_mps);
+ }
+
env->DeleteLocalRef(gpsMeasurementClass);
return gpsMeasurementObject;
}
-static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
- size_t measurementCount = data->measurement_count;
+/**
+ * <T> can only be GpsData or GpsData_v1. Must rewrite this function if more
+ * types are introduced in the future releases.
+ */
+template<class T>
+static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
+ T* gps_data = reinterpret_cast<T*>(data);
+ size_t measurementCount = gps_data->measurement_count;
if (measurementCount == 0) {
return NULL;
}
@@ -1221,9 +1327,11 @@
gpsMeasurementClass,
NULL /* initialElement */);
- GpsMeasurement* gpsMeasurements = data->measurements;
for (uint16_t i = 0; i < measurementCount; ++i) {
- jobject gpsMeasurement = translate_gps_measurement(env, &gpsMeasurements[i]);
+ jobject gpsMeasurement = translate_gps_measurement(
+ env,
+ &(gps_data->measurements[i]),
+ sizeof(gps_data->measurements[0]));
env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
env->DeleteLocalRef(gpsMeasurement);
}
@@ -1238,33 +1346,39 @@
ALOGE("Invalid data provided to gps_measurement_callback");
return;
}
-
- if (data->size == sizeof(GpsData)) {
- jobject gpsClock = translate_gps_clock(env, &data->clock);
- jobjectArray measurementArray = translate_gps_measurements(env, data);
-
- jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
- jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
- gpsMeasurementsEventClass,
- "<init>",
- "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
-
- jobject gpsMeasurementsEvent = env->NewObject(
- gpsMeasurementsEventClass,
- gpsMeasurementsEventCtor,
- gpsClock,
- measurementArray);
-
- env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- env->DeleteLocalRef(gpsClock);
- env->DeleteLocalRef(measurementArray);
- env->DeleteLocalRef(gpsMeasurementsEventClass);
- env->DeleteLocalRef(gpsMeasurementsEvent);
- } else {
+ if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
+ return;
}
+
+ jobject gpsClock;
+ jobjectArray measurementArray;
+ if (data->size == sizeof(GpsData)) {
+ gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock));
+ measurementArray = translate_gps_measurements<GpsData>(env, data);
+ } else {
+ gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock_v1));
+ measurementArray = translate_gps_measurements<GpsData_v1>(env, data);
+ }
+ jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
+ jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
+ gpsMeasurementsEventClass,
+ "<init>",
+ "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
+
+ jobject gpsMeasurementsEvent = env->NewObject(
+ gpsMeasurementsEventClass,
+ gpsMeasurementsEventCtor,
+ gpsClock,
+ measurementArray);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+ env->DeleteLocalRef(gpsClock);
+ env->DeleteLocalRef(measurementArray);
+ env->DeleteLocalRef(gpsMeasurementsEventClass);
+ env->DeleteLocalRef(gpsMeasurementsEvent);
}
GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
@@ -1272,7 +1386,7 @@
measurement_callback,
};
-static jboolean android_location_GpsLocationProvider_is_measurement_supported(
+static jboolean android_location_GnssLocationProvider_is_measurement_supported(
JNIEnv* env,
jclass clazz) {
if (sGpsMeasurementInterface != NULL) {
@@ -1281,7 +1395,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_start_measurement_collection(
+static jboolean android_location_GnssLocationProvider_start_measurement_collection(
JNIEnv* env,
jobject obj) {
if (sGpsMeasurementInterface == NULL) {
@@ -1298,7 +1412,7 @@
return JNI_TRUE;
}
-static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
+static jboolean android_location_GnssLocationProvider_stop_measurement_collection(
JNIEnv* env,
jobject obj) {
if (sGpsMeasurementInterface == NULL) {
@@ -1382,7 +1496,7 @@
navigation_message_callback,
};
-static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
+static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
JNIEnv* env,
jclass clazz) {
if(sGpsNavigationMessageInterface != NULL) {
@@ -1391,7 +1505,7 @@
return JNI_FALSE;
}
-static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
+static jboolean android_location_GnssLocationProvider_start_navigation_message_collection(
JNIEnv* env,
jobject obj) {
if (sGpsNavigationMessageInterface == NULL) {
@@ -1408,7 +1522,7 @@
return JNI_TRUE;
}
-static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
+static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection(
JNIEnv* env,
jobject obj) {
if (sGpsNavigationMessageInterface == NULL) {
@@ -1420,7 +1534,7 @@
return JNI_TRUE;
}
-static void android_location_GpsLocationProvider_configuration_update(JNIEnv* env, jobject obj,
+static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj,
jstring config_content)
{
if (!sGnssConfigurationInterface) {
@@ -1436,105 +1550,105 @@
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
- {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
- {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
+ {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native},
+ {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported},
{"native_is_agps_ril_supported", "()Z",
- (void*)android_location_GpsLocationProvider_is_agps_ril_supported},
+ (void*)android_location_GnssLocationProvider_is_agps_ril_supported},
{"native_is_gnss_configuration_supported", "()Z",
(void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
- {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
- {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
+ {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init},
+ {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup},
{"native_set_position_mode",
"(IIIII)Z",
- (void*)android_location_GpsLocationProvider_set_position_mode},
- {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
- {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
+ (void*)android_location_GnssLocationProvider_set_position_mode},
+ {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start},
+ {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop},
{"native_delete_aiding_data",
"(I)V",
- (void*)android_location_GpsLocationProvider_delete_aiding_data},
+ (void*)android_location_GnssLocationProvider_delete_aiding_data},
{"native_read_sv_status",
"([I[F[F[F[I)I",
- (void*)android_location_GpsLocationProvider_read_sv_status},
- {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
- {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+ (void*)android_location_GnssLocationProvider_read_sv_status},
+ {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
+ {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
{"native_inject_location",
"(DDF)V",
- (void*)android_location_GpsLocationProvider_inject_location},
- {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
+ (void*)android_location_GnssLocationProvider_inject_location},
+ {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra},
{"native_inject_xtra_data",
"([BI)V",
- (void*)android_location_GpsLocationProvider_inject_xtra_data},
+ (void*)android_location_GnssLocationProvider_inject_xtra_data},
{"native_agps_data_conn_open",
"(Ljava/lang/String;I)V",
- (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+ (void*)android_location_GnssLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed",
"()V",
- (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+ (void*)android_location_GnssLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed",
"()V",
- (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+ (void*)android_location_GnssLocationProvider_agps_data_conn_failed},
{"native_agps_set_id",
"(ILjava/lang/String;)V",
- (void*)android_location_GpsLocationProvider_agps_set_id},
+ (void*)android_location_GnssLocationProvider_agps_set_id},
{"native_agps_set_ref_location_cellid",
"(IIIII)V",
- (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
+ (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid},
{"native_set_agps_server",
"(ILjava/lang/String;I)V",
- (void*)android_location_GpsLocationProvider_set_agps_server},
+ (void*)android_location_GnssLocationProvider_set_agps_server},
{"native_send_ni_response",
"(II)V",
- (void*)android_location_GpsLocationProvider_send_ni_response},
+ (void*)android_location_GnssLocationProvider_send_ni_response},
{"native_agps_ni_message",
"([BI)V",
- (void *)android_location_GpsLocationProvider_agps_send_ni_message},
+ (void *)android_location_GnssLocationProvider_agps_send_ni_message},
{"native_get_internal_state",
"()Ljava/lang/String;",
- (void*)android_location_GpsLocationProvider_get_internal_state},
+ (void*)android_location_GnssLocationProvider_get_internal_state},
{"native_update_network_state",
"(ZIZZLjava/lang/String;Ljava/lang/String;)V",
- (void*)android_location_GpsLocationProvider_update_network_state },
+ (void*)android_location_GnssLocationProvider_update_network_state },
{"native_is_geofence_supported",
"()Z",
- (void*) android_location_GpsLocationProvider_is_geofence_supported},
+ (void*) android_location_GnssLocationProvider_is_geofence_supported},
{"native_add_geofence",
"(IDDDIIII)Z",
- (void *)android_location_GpsLocationProvider_add_geofence},
+ (void *)android_location_GnssLocationProvider_add_geofence},
{"native_remove_geofence",
"(I)Z",
- (void *)android_location_GpsLocationProvider_remove_geofence},
- {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
+ (void *)android_location_GnssLocationProvider_remove_geofence},
+ {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence},
{"native_resume_geofence",
"(II)Z",
- (void *)android_location_GpsLocationProvider_resume_geofence},
+ (void *)android_location_GnssLocationProvider_resume_geofence},
{"native_is_measurement_supported",
"()Z",
- (void*) android_location_GpsLocationProvider_is_measurement_supported},
+ (void*) android_location_GnssLocationProvider_is_measurement_supported},
{"native_start_measurement_collection",
"()Z",
- (void*) android_location_GpsLocationProvider_start_measurement_collection},
+ (void*) android_location_GnssLocationProvider_start_measurement_collection},
{"native_stop_measurement_collection",
"()Z",
- (void*) android_location_GpsLocationProvider_stop_measurement_collection},
+ (void*) android_location_GnssLocationProvider_stop_measurement_collection},
{"native_is_navigation_message_supported",
"()Z",
- (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
+ (void*) android_location_GnssLocationProvider_is_navigation_message_supported},
{"native_start_navigation_message_collection",
"()Z",
- (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
+ (void*) android_location_GnssLocationProvider_start_navigation_message_collection},
{"native_stop_navigation_message_collection",
"()Z",
- (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
+ (void*) android_location_GnssLocationProvider_stop_navigation_message_collection},
{"native_configuration_update",
"(Ljava/lang/String;)V",
- (void*)android_location_GpsLocationProvider_configuration_update},
+ (void*)android_location_GnssLocationProvider_configuration_update},
};
-int register_android_server_location_GpsLocationProvider(JNIEnv* env)
+int register_android_server_location_GnssLocationProvider(JNIEnv* env)
{
return jniRegisterNativeMethods(
env,
- "com/android/server/location/GpsLocationProvider",
+ "com/android/server/location/GnssLocationProvider",
sMethods,
NELEM(sMethods));
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1f3fde6..a7010bc 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,7 +36,7 @@
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
-int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_GnssLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
@@ -71,7 +71,7 @@
register_android_server_UsbHostManager(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
- register_android_server_location_GpsLocationProvider(env);
+ register_android_server_location_GnssLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4fd8990..7831c4d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -49,6 +49,7 @@
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
+import android.auditing.SecurityLog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -194,7 +195,7 @@
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
- protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
+ private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
@@ -471,6 +472,7 @@
private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture";
private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time";
+ private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users";
private static final String TAG_ACCOUNT_TYPE = "account-type";
private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES
= "permitted-accessiblity-services";
@@ -507,6 +509,7 @@
private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
private static final String TAG_PARENT_ADMIN = "parent-admin";
private static final String TAG_ORGANIZATION_COLOR = "organization-color";
+ private static final String TAG_ORGANIZATION_NAME = "organization-name";
final DeviceAdminInfo info;
@@ -559,6 +562,7 @@
boolean disableBluetoothContactSharing = true;
boolean disableScreenCapture = false; // Can only be set by a device/profile owner.
boolean requireAutoTime = false; // Can only be set by a device owner.
+ boolean forceEphemeralUsers = false; // Can only be set by a device owner.
ActiveAdmin parentAdmin;
final boolean isParent;
@@ -604,6 +608,9 @@
static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
int organizationColor = DEF_ORGANIZATION_COLOR;
+ // Default title of confirm credentials screen
+ String organizationName = null;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -749,6 +756,11 @@
out.attribute(null, ATTR_VALUE, Boolean.toString(requireAutoTime));
out.endTag(null, TAG_REQUIRE_AUTO_TIME);
}
+ if (forceEphemeralUsers) {
+ out.startTag(null, TAG_FORCE_EPHEMERAL_USERS);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(forceEphemeralUsers));
+ out.endTag(null, TAG_FORCE_EPHEMERAL_USERS);
+ }
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
@@ -822,6 +834,11 @@
out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
out.endTag(null, TAG_ORGANIZATION_COLOR);
}
+ if (organizationName != null) {
+ out.startTag(null, TAG_ORGANIZATION_NAME);
+ out.text(organizationName);
+ out.endTag(null, TAG_ORGANIZATION_NAME);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -919,7 +936,10 @@
disableScreenCapture = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) {
- requireAutoTime= Boolean.parseBoolean(
+ requireAutoTime = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) {
+ forceEphemeralUsers = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
@@ -960,6 +980,13 @@
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
organizationColor = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ organizationName = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading organization name");
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1150,6 +1177,8 @@
pw.println(disableScreenCapture);
pw.print(prefix); pw.print("requireAutoTime=");
pw.println(requireAutoTime);
+ pw.print(prefix); pw.print("forceEphemeralUsers=");
+ pw.println(forceEphemeralUsers);
pw.print(prefix); pw.print("disabledKeyguardFeatures=");
pw.println(disabledKeyguardFeatures);
pw.print(prefix); pw.print("crossProfileWidgetProviders=");
@@ -1166,6 +1195,12 @@
pw.print(prefix); pw.print("keepUninstalledPackages=");
pw.println(keepUninstalledPackages);
}
+ pw.print(prefix); pw.print("organizationColor=");
+ pw.println(organizationColor);
+ if (organizationName != null) {
+ pw.print(prefix); pw.print("organizationName=");
+ pw.println(organizationName);
+ }
pw.print(prefix); pw.println("userRestrictions:");
UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions);
pw.print(prefix); pw.print("isParent=");
@@ -1690,8 +1725,8 @@
* Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
* reminders. Clears alarm if no expirations are configured.
*/
- private void setExpirationAlarmCheckLocked(Context context, int userHandle) {
- final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false);
+ private void setExpirationAlarmCheckLocked(Context context, int userHandle, boolean parent) {
+ final long expiration = getPasswordExpirationLocked(null, userHandle, parent);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
@@ -1713,11 +1748,12 @@
long token = mInjector.binderClearCallingIdentity();
try {
+ int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
- UserHandle.of(userHandle));
+ UserHandle.of(affectedUserHandle));
am.cancel(pi);
if (alarmTime != 0) {
am.set(AlarmManager.RTC, alarmTime, pi);
@@ -1971,7 +2007,7 @@
final ResolveInfo ri = infos.get(0);
if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
- final String message = "DeviceAdminReceiver " + adminName + " must be protected with"
+ final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
+ permission.BIND_DEVICE_ADMIN;
Slog.w(LOG_TAG, message);
if (throwForMissiongPermission &&
@@ -2408,6 +2444,14 @@
if (packageList != null) {
mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList);
}
+
+ synchronized (this) {
+ // push the force-ephemeral-users policy to the user manager.
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ if (deviceOwner != null) {
+ mUserManagerInternal.setForceEphemeralUsers(deviceOwner.forceEphemeralUsers);
+ }
+ }
}
private void ensureDeviceOwnerUserStarted() {
@@ -2468,7 +2512,6 @@
synchronized (this) {
final long now = System.currentTimeMillis();
- // Return the strictest policy across all participating admins.
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
userHandle, /* parent */ false);
final int N = admins.size();
@@ -2482,7 +2525,7 @@
DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
}
}
@@ -2955,8 +2998,7 @@
saveSettingsLocked(userHandle);
// in case this is the first one, set the alarm on the appropriate user.
- int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
- setExpirationAlarmCheckLocked(mContext, affectedUserHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, parent);
}
}
@@ -4303,7 +4345,7 @@
policy.mFailedPasswordAttempts = 0;
saveSettingsLocked(userHandle);
updatePasswordExpirationsLocked(userHandle);
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
// Send a broadcast to each profile using this password as its primary unlock.
sendAdminCommandForLockscreenPoliciesLocked(
@@ -4381,6 +4423,10 @@
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
+
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0);
+ }
}
@Override
@@ -4407,6 +4453,28 @@
}
}
}
+
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1);
+ }
+ }
+
+ @Override
+ public void reportKeyguardDismissed() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
+ }
+ }
+
+ @Override
+ public void reportKeyguardSecured() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
+ }
}
@Override
@@ -4789,6 +4857,46 @@
}
}
+ @Override
+ public void setForceEphemeralUsers(ComponentName who, boolean forceEphemeralUsers) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ boolean removeAllUsers = false;
+ synchronized (this) {
+ final ActiveAdmin deviceOwner =
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ if (deviceOwner.forceEphemeralUsers != forceEphemeralUsers) {
+ deviceOwner.forceEphemeralUsers = forceEphemeralUsers;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ mUserManagerInternal.setForceEphemeralUsers(forceEphemeralUsers);
+ removeAllUsers = forceEphemeralUsers;
+ }
+ }
+ if (removeAllUsers) {
+ long identitity = mInjector.binderClearCallingIdentity();
+ try {
+ mUserManagerInternal.removeAllUsers();
+ } finally {
+ mInjector.binderRestoreCallingIdentity(identitity);
+ }
+ }
+ }
+
+ @Override
+ public boolean getForceEphemeralUsers(ComponentName who) {
+ if (!mHasFeature) {
+ return false;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ final ActiveAdmin deviceOwner =
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ return deviceOwner.forceEphemeralUsers;
+ }
+ }
+
private void ensureDeviceOwnerManagingSingleUser(ComponentName who) throws SecurityException {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -5319,6 +5427,8 @@
if (admin != null) {
admin.disableCamera = false;
admin.userRestrictions = null;
+ admin.forceEphemeralUsers = false;
+ mUserManagerInternal.setForceEphemeralUsers(admin.forceEphemeralUsers);
}
clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
@@ -5361,7 +5471,9 @@
if (!mHasFeature) {
return;
}
- UserHandle callingUser = mInjector.binderGetCallingUserHandle();
+ final UserHandle callingUser = mInjector.binderGetCallingUserHandle();
+ final int userId = callingUser.getIdentifier();
+ enforceNotManagedProfile(userId, "clear profile owner");
// Check if this is the profile owner who is calling
final ActiveAdmin admin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5369,7 +5481,6 @@
admin.disableCamera = false;
admin.userRestrictions = null;
clearUserPoliciesLocked(callingUser);
- final int userId = callingUser.getIdentifier();
mOwners.removeProfileOwner(userId);
mOwners.writeProfileOwner(userId);
}
@@ -6682,6 +6793,8 @@
@Override
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
Preconditions.checkNotNull(who, "ComponentName is null");
+ UserRestrictionsUtils.checkRestriction(key);
+
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin activeAdmin =
@@ -8007,11 +8120,12 @@
@Override
public void setOrganizationColor(@NonNull ComponentName who, int color) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8022,11 +8136,11 @@
@Override
public int getOrganizationColor(@NonNull ComponentName who) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8036,10 +8150,11 @@
@Override
public int getOrganizationColorForUser(int userHandle) {
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceCrossUsersPermission(userHandle);
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization color");
synchronized (this) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -8049,6 +8164,53 @@
}
@Override
+ public void setOrganizationName(@NonNull ComponentName who, String text) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization name");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(admin.organizationName, text)) {
+ admin.organizationName = TextUtils.nullIfEmpty(text);
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getOrganizationName(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ synchronized(this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.organizationName;
+ }
+ }
+
+ @Override
+ public String getOrganizationNameForUser(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization name");
+ synchronized (this) {
+ ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+ return (profileOwner != null)
+ ? profileOwner.organizationName
+ : null;
+ }
+ }
+
+ @Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
final Set<String> affiliationIds = new ArraySet<String>(ids);
final int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c186a12..254a37a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -68,6 +68,7 @@
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsService;
+import com.android.internal.widget.ILockSettings;
import com.android.server.media.MediaRouterService;
import com.android.server.media.MediaSessionService;
import com.android.server.media.MediaResourceMonitorService;
@@ -84,6 +85,7 @@
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.restrictions.RestrictionsManagerService;
+import com.android.server.soundtrigger.SoundTriggerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
import com.android.server.telecom.TelecomLoaderService;
@@ -142,6 +144,8 @@
"com.android.server.ethernet.EthernetService";
private static final String JOB_SCHEDULER_SERVICE_CLASS =
"com.android.server.job.JobSchedulerService";
+ private static final String LOCK_SETTINGS_SERVICE_CLASS =
+ "com.android.server.LockSettingsService$Lifecycle";
private static final String MOUNT_SERVICE_CLASS =
"com.android.server.MountService$Lifecycle";
private static final String SEARCH_MANAGER_SERVICE_CLASS =
@@ -606,7 +610,7 @@
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
TextServicesManagerService tsms = null;
- LockSettingsService lockSettings = null;
+ ILockSettings lockSettings = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
@@ -679,8 +683,9 @@
if (!disableNonCoreServices) {
traceBeginAndSlog("StartLockSettingsService");
try {
- lockSettings = new LockSettingsService(context);
- ServiceManager.addService("lock_settings", lockSettings);
+ mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+ lockSettings = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
} catch (Throwable e) {
reportWtf("starting LockSettingsService service", e);
}
@@ -959,6 +964,8 @@
mSystemServiceManager.startService(JobSchedulerService.class);
+ mSystemServiceManager.startService(SoundTriggerService.class);
+
if (!disableNonCoreServices) {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
@@ -976,6 +983,7 @@
Slog.i(TAG, "Gesture Launcher Service");
mSystemServiceManager.startService(GestureLauncherService.class);
}
+ mSystemServiceManager.startService(SensorNotificationService.class);
}
traceBeginAndSlog("StartDiskStatsService");
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 27d5207..5874429 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -52,10 +52,12 @@
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
+import android.os.Messenger;
import android.os.MessageQueue.IdleHandler;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@@ -1298,6 +1300,36 @@
validatedCallback.expectCallback(CallbackState.LOST);
}
+ @SmallTest
+ public void testInvalidNetworkSpecifier() {
+ boolean execptionCalled = true;
+
+ try {
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+ execptionCalled = false;
+ } catch (IllegalArgumentException e) {
+ // do nothing - should get here
+ }
+
+ assertTrue("NetworkReqeuest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+ execptionCalled);
+
+ try {
+ NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addTransportType(TRANSPORT_WIFI)
+ .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+ mService.requestNetwork(networkCapabilities, null, 0, null,
+ ConnectivityManager.TYPE_WIFI);
+ execptionCalled = false;
+ } catch (IllegalArgumentException e) {
+ // do nothing - should get here
+ }
+
+ assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+ execptionCalled);
+ }
+
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b4bca3e..6c2fcd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -26,7 +26,10 @@
import android.os.UserManager;
import android.test.AndroidTestCase;
+import com.android.internal.util.ArrayUtils;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/** Test {@link UserManager} functionality. */
@@ -196,6 +199,17 @@
assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
}
+ public void testGetSerialNumbersOfUsers() {
+ UserInfo user1 = createUser("User 1", 0);
+ UserInfo user2 = createUser("User 2", 0);
+ long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
+ String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
+ assertTrue(errMsg + user1.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
+ assertTrue(errMsg + user2.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+ }
+
public void testMaxUsers() {
int N = UserManager.getMaxSupportedUsers();
int count = mUserManager.getUsers().size();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81031da..77740387 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
+ static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
private final Object mLock = new Object();
Handler mHandler;
@@ -144,8 +145,10 @@
private boolean mScreenOn;
private long mLastAppIdleParoledTime;
+ private volatile boolean mPendingOneTimeCheckIdleStates;
+
long mScreenOnTime;
- long mScreenOnSystemTimeSnapshot;
+ long mLastScreenOnEventRealtime;
@GuardedBy("mLock")
private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +191,8 @@
synchronized (mLock) {
cleanUpRemovedUsersLocked();
+ mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+ mScreenOnTime = readScreenOnTimeLocked();
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,14 +219,14 @@
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
- mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
- synchronized (mLock) {
- mScreenOnTime = readScreenOnTimeLocked();
- }
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
synchronized (mLock) {
updateDisplayLocked();
}
+
+ if (mPendingOneTimeCheckIdleStates) {
+ postOneTimeCheckIdleStates();
+ }
} else if (phase == PHASE_BOOT_COMPLETED) {
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
}
@@ -281,6 +286,11 @@
}
@Override
+ public void onStatsReloaded() {
+ postOneTimeCheckIdleStates();
+ }
+
+ @Override
public long getAppIdleRollingWindowDurationMillis() {
return mAppIdleWallclockThresholdMillis * 2;
}
@@ -359,6 +369,20 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
+ /**
+ * We send a different message to check idle states once, otherwise we would end up
+ * scheduling a series of repeating checkIdleStates each time we fired off one.
+ */
+ void postOneTimeCheckIdleStates() {
+ if (mDeviceIdleController == null) {
+ // Not booted yet; wait for it!
+ mPendingOneTimeCheckIdleStates = true;
+ } else {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ mPendingOneTimeCheckIdleStates = false;
+ }
+ }
+
/** Check all running users' or specified user's apps to see if they enter an idle state. */
void checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
@@ -385,7 +409,7 @@
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
timeNow);
final int packageCount = packages.size();
@@ -401,8 +425,6 @@
}
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
- mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -443,21 +465,21 @@
if (screenOn == mScreenOn) return;
mScreenOn = screenOn;
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
if (mScreenOn) {
- mScreenOnSystemTimeSnapshot = now;
+ mLastScreenOnEventRealtime = now;
} else {
- mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+ mScreenOnTime += now - mLastScreenOnEventRealtime;
writeScreenOnTimeLocked(mScreenOnTime);
}
}
- private long getScreenOnTimeLocked(long now) {
+ long getScreenOnTimeLocked() {
+ long screenOnTime = mScreenOnTime;
if (mScreenOn) {
- return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
- } else {
- return mScreenOnTime;
+ screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
}
+ return screenOnTime;
}
private File getScreenOnTimeFile() {
@@ -527,7 +549,7 @@
if (service == null) {
service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
- service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+ service.init(currentTimeMillis, getScreenOnTimeLocked());
mUserState.put(userId, service);
}
return service;
@@ -540,25 +562,18 @@
final long actualSystemTime = System.currentTimeMillis();
final long actualRealtime = SystemClock.elapsedRealtime();
final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
- boolean resetBeginIdleTime = false;
- if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+ final long diffSystemTime = actualSystemTime - expectedSystemTime;
+ if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
// The time has changed.
-
- // Check if it's severe enough a change to reset screenOnTime
- if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
- mScreenOnSystemTimeSnapshot = actualSystemTime;
- mScreenOnTime = 0;
- resetBeginIdleTime = true;
- }
+ Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
- resetBeginIdleTime);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+ false);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
- postCheckIdleStates(UserHandle.USER_ALL);
}
return actualSystemTime;
}
@@ -587,7 +602,7 @@
void reportEvent(UsageEvents.Event event, int userId) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
convertToSystemTimeLocked(event);
final UserUsageStatsService service =
@@ -603,7 +618,6 @@
|| event.mEventType == Event.SYSTEM_INTERACTION
|| event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
- //Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
@@ -643,7 +657,7 @@
void forceIdleState(String packageName, int userId, boolean idle) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
final UserUsageStatsService service =
@@ -657,7 +671,6 @@
timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
if (!idle) {
@@ -796,7 +809,7 @@
timeNow = checkAndGetTimeLocked();
}
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
userService, timeNow, screenOnTime);
@@ -865,7 +878,7 @@
synchronized (mLock) {
timeNow = checkAndGetTimeLocked();
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
List<ApplicationInfo> apps;
@@ -987,7 +1000,7 @@
*/
void dump(String[] args, PrintWriter pw) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+ final long screenOnTime = getScreenOnTimeLocked();
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
ArraySet<String> argSet = new ArraySet<>();
argSet.addAll(Arrays.asList(args));
@@ -1008,7 +1021,11 @@
}
idpw.decreaseIndent();
}
- pw.println("Screen On Timebase:" + mScreenOnTime);
+ pw.print("Screen On Timebase: ");
+ pw.print(screenOnTime);
+ pw.print(" (");
+ TimeUtils.formatDuration(screenOnTime, pw);
+ pw.println(")");
pw.println();
pw.println("Settings:");
@@ -1042,8 +1059,8 @@
pw.println();
pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
pw.println();
- pw.print("mScreenOnSystemTimeSnapshot=");
- TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+ pw.print("mLastScreenOnEventRealtime=");
+ TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
pw.println();
}
}
@@ -1078,6 +1095,14 @@
case MSG_CHECK_IDLE_STATES:
checkIdleStates(msg.arg1);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ break;
+
+ case MSG_ONE_TIME_CHECK_IDLE_STATES:
+ mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ checkIdleStates(UserHandle.USER_ALL);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1138,7 +1163,7 @@
@Override
public void onChange(boolean selfChange) {
updateSettings();
- postCheckIdleStates(UserHandle.USER_ALL);
+ postOneTimeCheckIdleStates();
}
void updateSettings() {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index aa2cf77..f2045d3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -73,6 +73,7 @@
interface StatsUpdatedListener {
void onStatsUpdated();
+ void onStatsReloaded();
long getAppIdleRollingWindowDurationMillis();
}
@@ -523,6 +524,9 @@
mStatsChanged = false;
updateRolloverDeadline();
+
+ // Tell the listener that the stats reloaded, which may have changed idle states.
+ mListener.onStatsReloaded();
}
private void updateRolloverDeadline() {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
new file mode 100644
index 0000000..18a5d59
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * Helper to manage the database of the sound models that have been registered on the device.
+ *
+ * @hide
+ */
+public class SoundTriggerDbHelper extends SQLiteOpenHelper {
+ static final String TAG = "SoundTriggerDbHelper";
+ static final boolean DBG = false;
+
+ private static final String NAME = "st_sound_model.db";
+ private static final int VERSION = 1;
+
+ // Sound trigger-based sound models.
+ public static interface GenericSoundModelContract {
+ public static final String TABLE = "st_sound_model";
+ public static final String KEY_MODEL_UUID = "model_uuid";
+ public static final String KEY_VENDOR_UUID = "vendor_uuid";
+ public static final String KEY_DATA = "data";
+ }
+
+
+ // Table Create Statement for the sound trigger table
+ private static final String CREATE_TABLE_ST_SOUND_MODEL = "CREATE TABLE "
+ + GenericSoundModelContract.TABLE + "("
+ + GenericSoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
+ + GenericSoundModelContract.KEY_DATA + " BLOB" + " )";
+
+
+ public SoundTriggerDbHelper(Context context) {
+ super(context, NAME, null, VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // creating required tables
+ db.execSQL(CREATE_TABLE_ST_SOUND_MODEL);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO: For now, drop older tables and recreate new ones.
+ db.execSQL("DROP TABLE IF EXISTS " + GenericSoundModelContract.TABLE);
+ onCreate(db);
+ }
+
+ /**
+ * Updates the given sound trigger model, adds it, if it doesn't already exist.
+ *
+ */
+ public boolean updateGenericSoundModel(GenericSoundModel soundModel) {
+ synchronized(this) {
+ SQLiteDatabase db = getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(GenericSoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString());
+ values.put(GenericSoundModelContract.KEY_VENDOR_UUID, soundModel.vendorUuid.toString());
+ values.put(GenericSoundModelContract.KEY_DATA, soundModel.data);
+
+ try {
+ return db.insertWithOnConflict(GenericSoundModelContract.TABLE, null, values,
+ SQLiteDatabase.CONFLICT_REPLACE) != -1;
+ } finally {
+ db.close();
+ }
+
+ }
+ }
+
+ public GenericSoundModel getGenericSoundModel(UUID model_uuid) {
+ synchronized(this) {
+
+ // Find the corresponding sound model ID for the keyphrase.
+ String selectQuery = "SELECT * FROM " + GenericSoundModelContract.TABLE
+ + " WHERE " + GenericSoundModelContract.KEY_MODEL_UUID + "= '" +
+ model_uuid + "'";
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor c = db.rawQuery(selectQuery, null);
+ try {
+ if (c.moveToFirst()) {
+ do {
+ byte[] data = c.getBlob(c.getColumnIndex(
+ GenericSoundModelContract.KEY_DATA));
+ String vendor_uuid = c.getString(
+ c.getColumnIndex(GenericSoundModelContract.KEY_VENDOR_UUID));
+ return new GenericSoundModel(model_uuid, UUID.fromString(vendor_uuid),
+ data);
+ } while (c.moveToNext());
+ }
+ } finally {
+ c.close();
+ db.close();
+ }
+ }
+ return null;
+ }
+
+ public boolean deleteGenericSoundModel(UUID model_uuid) {
+ synchronized(this) {
+ GenericSoundModel soundModel = getGenericSoundModel(model_uuid);
+ if (soundModel == null) {
+ return false;
+ }
+ // Delete all sound models for the given keyphrase and specified user.
+ SQLiteDatabase db = getWritableDatabase();
+ String soundModelClause = GenericSoundModelContract.KEY_MODEL_UUID
+ + "='" + soundModel.uuid.toString() + "'";
+ try {
+ return db.delete(GenericSoundModelContract.TABLE, soundModelClause, null) != 0;
+ } finally {
+ db.close();
+ }
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
similarity index 99%
rename from services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
rename to services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 31d859f..597f915ec 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.voiceinteraction;
+package com.android.server.soundtrigger;
import android.content.BroadcastReceiver;
import android.content.Context;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
new file mode 100644
index 0000000..0a06bfa
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
+import android.hardware.soundtrigger.SoundTriggerModule;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Provides a local service for managing voice-related recoginition models. This is primarily used
+ * by the {@link VoiceInteractionManagerService}.
+ */
+public abstract class SoundTriggerInternal {
+ /**
+ * Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
+ * IRecognitionStatusCallback, RecognitionConfig)},
+ * {@link #stopRecognition(int, IRecognitionStatusCallback)}
+ */
+ public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
+ public static final int STATUS_OK = SoundTrigger.STATUS_OK;
+
+ /** The {@link ModuleProperties} for the system, or null if none exists. */
+ private ModuleProperties moduleProperties;
+
+ /**
+ * Starts recognition for the given keyphraseId.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * the recognition is to be started.
+ * @param soundModel The sound model to use for recognition.
+ * @param listener The listener for the recognition events related to the given keyphrase.
+ * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+ */
+ public abstract int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
+ IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig);
+
+ /**
+ * Stops recognition for the given {@link Keyphrase} if a recognition is
+ * currently active.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * the recognition is to be stopped.
+ * @param listener The listener for the recognition events related to the given keyphrase.
+ *
+ * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+ */
+ public abstract int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener);
+
+ /**
+ * Stops all recognitions active currently and clears the internal state.
+ */
+ public abstract void stopAllRecognitions();
+
+ public ModuleProperties getModuleProperties() {
+ return moduleProperties;
+ }
+
+ public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
new file mode 100644
index 0000000..5e8fe9e
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.Manifest;
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+import com.android.internal.app.ISoundTriggerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.UUID;
+
+/**
+ * A single SystemService to manage all sound/voice-based sound models on the DSP.
+ * This services provides apis to manage sound trigger-based sound models via
+ * the ISoundTriggerService interface. This class also publishes a local interface encapsulating
+ * the functionality provided by {@link SoundTriggerHelper} for use by
+ * {@link VoiceInteractionManagerService}.
+ *
+ * @hide
+ */
+public class SoundTriggerService extends SystemService {
+ static final String TAG = "SoundTriggerService";
+ static final boolean DEBUG = false;
+
+ final Context mContext;
+ private final SoundTriggerServiceStub mServiceStub;
+ private final LocalSoundTriggerService mLocalSoundTriggerService;
+ private SoundTriggerDbHelper mDbHelper;
+
+ public SoundTriggerService(Context context) {
+ super(context);
+ mContext = context;
+ mServiceStub = new SoundTriggerServiceStub();
+ mLocalSoundTriggerService = new LocalSoundTriggerService(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.SOUND_TRIGGER_SERVICE, mServiceStub);
+ publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ mLocalSoundTriggerService.initSoundTriggerHelper();
+ } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
+ mDbHelper = new SoundTriggerDbHelper(mContext);
+ }
+ }
+
+ @Override
+ public void onStartUser(int userHandle) {
+ }
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ }
+
+ class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ // The activity manager only throws security exceptions, so let's
+ // log all others.
+ if (!(e instanceof SecurityException)) {
+ Slog.wtf(TAG, "SoundTriggerService Crash", e);
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public void startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (DEBUG) {
+ Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
+ }
+ }
+
+ @Override
+ public void stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (DEBUG) {
+ Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
+ }
+ }
+
+ @Override
+ public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (DEBUG) {
+ Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
+ }
+ SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(soundModelId.getUuid());
+ if (model == null) {
+ Slog.e(TAG, "Null model in database.");
+ }
+ return model;
+ }
+
+ @Override
+ public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (DEBUG) {
+ Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
+ }
+ mDbHelper.updateGenericSoundModel(soundModel);
+ }
+
+ @Override
+ public void deleteSoundModel(ParcelUuid soundModelId) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (DEBUG) {
+ Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
+ }
+ mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
+ }
+ }
+
+ public final class LocalSoundTriggerService extends SoundTriggerInternal {
+ private final Context mContext;
+ private SoundTriggerHelper mSoundTriggerHelper;
+
+ LocalSoundTriggerService(Context context) {
+ mContext = context;
+ }
+
+ void initSoundTriggerHelper() {
+ if (mSoundTriggerHelper == null) {
+ mSoundTriggerHelper = new SoundTriggerHelper(mContext);
+ }
+ }
+
+ @Override
+ public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
+ IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
+ return mSoundTriggerHelper.startRecognition(keyphraseId, soundModel, listener,
+ recognitionConfig);
+ }
+
+ @Override
+ public int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
+ return mSoundTriggerHelper.stopRecognition(keyphraseId, listener);
+ }
+
+ @Override
+ public void stopAllRecognitions() {
+ mSoundTriggerHelper.stopAllRecognitions();
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mSoundTriggerHelper.dump(fd, pw, args);
+ }
+ }
+
+ private void enforceCallingPermission(String permission) {
+ if (mContext.checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold the permission " + permission);
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 2aef109..4a54643 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -62,6 +62,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
+import com.android.server.soundtrigger.SoundTriggerInternal;
import com.android.server.SystemService;
import com.android.server.UiThread;
@@ -79,15 +80,14 @@
final Context mContext;
final ContentResolver mResolver;
final DatabaseHelper mDbHelper;
- final SoundTriggerHelper mSoundTriggerHelper;
final ActivityManagerInternal mAmInternal;
+ SoundTriggerInternal mSoundTriggerInternal;
public VoiceInteractionManagerService(Context context) {
super(context);
mContext = context;
mResolver = context.getContentResolver();
mDbHelper = new DatabaseHelper(context);
- mSoundTriggerHelper = new SoundTriggerHelper(context);
mServiceStub = new VoiceInteractionManagerServiceStub();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -115,7 +115,9 @@
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
+ } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mServiceStub.systemRunning(isSafeMode());
}
}
@@ -380,7 +382,7 @@
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
- mSoundTriggerHelper.stopAllRecognitions();
+ mSoundTriggerInternal.stopAllRecognitions();
if (mImpl != null) {
mImpl.shutdownLocked();
}
@@ -736,9 +738,9 @@
mImpl.notifySoundModelsChangedLocked();
}
}
- return SoundTriggerHelper.STATUS_OK;
+ return SoundTriggerInternal.STATUS_OK;
} else {
- return SoundTriggerHelper.STATUS_ERROR;
+ return SoundTriggerInternal.STATUS_ERROR;
}
} finally {
Binder.restoreCallingIdentity(caller);
@@ -759,7 +761,7 @@
boolean deleted = false;
try {
deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
- return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR;
+ return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
} finally {
if (deleted) {
synchronized (this) {
@@ -812,7 +814,7 @@
final long caller = Binder.clearCallingIdentity();
try {
- return mSoundTriggerHelper.moduleProperties;
+ return mSoundTriggerInternal.getModuleProperties();
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -845,9 +847,9 @@
|| soundModel.uuid == null
|| soundModel.keyphrases == null) {
Slog.w(TAG, "No matching sound model found in startRecognition");
- return SoundTriggerHelper.STATUS_ERROR;
+ return SoundTriggerInternal.STATUS_ERROR;
} else {
- return mSoundTriggerHelper.startRecognition(
+ return mSoundTriggerInternal.startRecognition(
keyphraseId, soundModel, callback, recognitionConfig);
}
} finally {
@@ -869,7 +871,7 @@
final long caller = Binder.clearCallingIdentity();
try {
- return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
+ return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -1011,7 +1013,7 @@
}
mImpl.dumpLocked(fd, pw, args);
}
- mSoundTriggerHelper.dump(fd, pw, args);
+ mSoundTriggerInternal.dump(fd, pw, args);
}
private void enforceCallingPermission(String permission) {
@@ -1060,7 +1062,7 @@
// The user is force stopping our current interactor/recognizer.
// Clear the current settings and restore default state.
synchronized (VoiceInteractionManagerService.this) {
- mSoundTriggerHelper.stopAllRecognitions();
+ mSoundTriggerInternal.stopAllRecognitions();
if (mImpl != null) {
mImpl.shutdownLocked();
mImpl = null;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3859294..de90202 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -265,6 +265,7 @@
// Next PROPERTY value: 0x00000040
//******************************************************************************************
+ private final String mTelecomCallId;
private final Uri mHandle;
private final int mHandlePresentation;
private final String mCallerDisplayName;
@@ -414,6 +415,11 @@
return builder.toString();
}
+ /** {@hide} */
+ public String getTelecomCallId() {
+ return mTelecomCallId;
+ }
+
/**
* @return The handle (e.g., phone number) to which the {@code Call} is currently
* connected.
@@ -567,6 +573,7 @@
/** {@hide} */
public Details(
+ String telecomCallId,
Uri handle,
int handlePresentation,
String callerDisplayName,
@@ -581,6 +588,7 @@
StatusHints statusHints,
Bundle extras,
Bundle intentExtras) {
+ mTelecomCallId = telecomCallId;
mHandle = handle;
mHandlePresentation = handlePresentation;
mCallerDisplayName = callerDisplayName;
@@ -596,6 +604,26 @@
mExtras = extras;
mIntentExtras = intentExtras;
}
+
+ /** {@hide} */
+ public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
+ return new Details(
+ parcelableCall.getId(),
+ parcelableCall.getHandle(),
+ parcelableCall.getHandlePresentation(),
+ parcelableCall.getCallerDisplayName(),
+ parcelableCall.getCallerDisplayNamePresentation(),
+ parcelableCall.getAccountHandle(),
+ parcelableCall.getCapabilities(),
+ parcelableCall.getProperties(),
+ parcelableCall.getDisconnectCause(),
+ parcelableCall.getConnectTimeMillis(),
+ parcelableCall.getGatewayInfo(),
+ parcelableCall.getVideoState(),
+ parcelableCall.getStatusHints(),
+ parcelableCall.getExtras(),
+ parcelableCall.getIntentExtras());
+ }
}
public static abstract class Callback {
@@ -1022,21 +1050,7 @@
/** {@hide} */
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
// First, we update the internal state as far as possible before firing any updates.
- Details details = new Details(
- parcelableCall.getHandle(),
- parcelableCall.getHandlePresentation(),
- parcelableCall.getCallerDisplayName(),
- parcelableCall.getCallerDisplayNamePresentation(),
- parcelableCall.getAccountHandle(),
- parcelableCall.getCapabilities(),
- parcelableCall.getProperties(),
- parcelableCall.getDisconnectCause(),
- parcelableCall.getConnectTimeMillis(),
- parcelableCall.getGatewayInfo(),
- parcelableCall.getVideoState(),
- parcelableCall.getStatusHints(),
- parcelableCall.getExtras(),
- parcelableCall.getIntentExtras());
+ Details details = Details.createFromParcelableCall(parcelableCall);
boolean detailsChanged = !Objects.equals(mDetails, details);
if (detailsChanged) {
mDetails = details;
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
new file mode 100644
index 0000000..f62b170
--- /dev/null
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecom.ICallScreeningService;
+import com.android.internal.telecom.ICallScreeningAdapter;
+
+/**
+ * This service can be implemented by the default dialer (see
+ * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before
+ * they are shown to a user.
+ * <p>
+ * Below is an example manifest registration for a {@code CallScreeningService}.
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourCallScreeningServiceImplementation"
+ * android:permission="android.permission.BIND_SCREENING_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.telecom.CallScreeningService"/>
+ * </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public abstract class CallScreeningService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+
+ private static final int MSG_SCREEN_CALL = 1;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SCREEN_CALL:
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
+ onScreenCall(
+ Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ }
+ };
+
+ private final class CallScreeningBinder extends ICallScreeningService.Stub {
+ @Override
+ public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
+ Log.v(this, "screenCall");
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = adapter;
+ args.arg2 = call;
+ mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
+ }
+ }
+
+ private ICallScreeningAdapter mCallScreeningAdapter;
+
+ /*
+ * Information about how to respond to an incoming call.
+ */
+ public static class CallResponse {
+ private final boolean mShouldDisallowCall;
+ private final boolean mShouldRejectCall;
+ private final boolean mShouldSkipCallLog;
+ private final boolean mShouldSkipNotification;
+
+ private CallResponse(
+ boolean shouldDisallowCall,
+ boolean shouldRejectCall,
+ boolean shouldSkipCallLog,
+ boolean shouldSkipNotification) {
+ if (!shouldDisallowCall
+ && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
+ throw new IllegalStateException("Invalid response state for allowed call.");
+ }
+
+ mShouldDisallowCall = shouldDisallowCall;
+ mShouldRejectCall = shouldRejectCall;
+ mShouldSkipCallLog = shouldSkipCallLog;
+ mShouldSkipNotification = shouldSkipNotification;
+ }
+
+ /*
+ * @return Whether the incoming call should be blocked.
+ */
+ public boolean getDisallowCall() {
+ return mShouldDisallowCall;
+ }
+
+ /*
+ * @return Whether the incoming call should be disconnected as if the user had manually
+ * rejected it.
+ */
+ public boolean getRejectCall() {
+ return mShouldRejectCall;
+ }
+
+ /*
+ * @return Whether the incoming call should not be displayed in the call log.
+ */
+ public boolean getSkipCallLog() {
+ return mShouldSkipCallLog;
+ }
+
+ /*
+ * @return Whether a missed call notification should not be shown for the incoming call.
+ */
+ public boolean getSkipNotification() {
+ return mShouldSkipNotification;
+ }
+
+ public static class Builder {
+ private boolean mShouldDisallowCall;
+ private boolean mShouldRejectCall;
+ private boolean mShouldSkipCallLog;
+ private boolean mShouldSkipNotification;
+
+ /*
+ * Sets whether the incoming call should be blocked.
+ */
+ public Builder setDisallowCall(boolean shouldDisallowCall) {
+ mShouldDisallowCall = shouldDisallowCall;
+ return this;
+ }
+
+ /*
+ * Sets whether the incoming call should be disconnected as if the user had manually
+ * rejected it. This property should only be set to true if the call is disallowed.
+ */
+ public Builder setRejectCall(boolean shouldRejectCall) {
+ mShouldRejectCall = shouldRejectCall;
+ return this;
+ }
+
+ /*
+ * Sets whether the incoming call should not be displayed in the call log. This property
+ * should only be set to true if the call is disallowed.
+ */
+ public Builder setSkipCallLog(boolean shouldSkipCallLog) {
+ mShouldSkipCallLog = shouldSkipCallLog;
+ return this;
+ }
+
+ /*
+ * Sets whether a missed call notification should not be shown for the incoming call.
+ * This property should only be set to true if the call is disallowed.
+ */
+ public Builder setSkipNotification(boolean shouldSkipNotification) {
+ mShouldSkipNotification = shouldSkipNotification;
+ return this;
+ }
+
+ public CallResponse build() {
+ return new CallResponse(
+ mShouldDisallowCall,
+ mShouldRejectCall,
+ mShouldSkipCallLog,
+ mShouldSkipNotification);
+ }
+ }
+ }
+
+ public CallScreeningService() {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.v(this, "onBind");
+ return new CallScreeningBinder();
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.v(this, "onUnbind");
+ return false;
+ }
+
+ /**
+ * Called when a new incoming call is added.
+ * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
+ * should be called to allow or disallow the call.
+ *
+ * @param callDetails Information about a new incoming call, see {@link Call.Details}.
+ */
+ public abstract void onScreenCall(Call.Details callDetails);
+
+ /**
+ * Responds to the given call, either allowing it or disallowing it.
+ *
+ * @param callDetails The call to allow.
+ * @param response The {@link CallScreeningService.CallResponse} which contains information
+ * about how to respond to a call.
+ */
+ public final void respondToCall(Call.Details callDetails, CallResponse response) {
+ try {
+ if (response.getDisallowCall()) {
+ mCallScreeningAdapter.disallowCall(
+ callDetails.getTelecomCallId(),
+ response.getRejectCall(),
+ !response.getSkipCallLog(),
+ !response.getSkipNotification());
+ } else {
+ mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
+ }
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 426b240..671399b 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -73,6 +73,7 @@
private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 5;
private static final int MSG_BRING_TO_FOREGROUND = 6;
private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
+ private static final int MSG_SILENCE_RINGER = 8;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -114,6 +115,9 @@
case MSG_ON_CAN_ADD_CALL_CHANGED:
mPhone.internalSetCanAddCall(msg.arg1 == 1);
break;
+ case MSG_SILENCE_RINGER:
+ mPhone.internalSilenceRinger();
+ break;
default:
break;
}
@@ -165,6 +169,11 @@
mHandler.obtainMessage(MSG_ON_CAN_ADD_CALL_CHANGED, canAddCall ? 1 : 0, 0)
.sendToTarget();
}
+
+ @Override
+ public void silenceRinger() {
+ mHandler.obtainMessage(MSG_SILENCE_RINGER).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
@@ -202,6 +211,12 @@
InCallService.this.onCanAddCallChanged(canAddCall);
}
+ /** ${inheritDoc} */
+ @Override
+ public void onSilenceRinger(Phone phone) {
+ InCallService.this.onSilenceRinger();
+ }
+
};
private Phone mPhone;
@@ -405,6 +420,12 @@
}
/**
+ * Called to silence the ringer if a ringing call exists.
+ */
+ public void onSilenceRinger() {
+ }
+
+ /**
* Used to issue commands to the {@link Connection.VideoProvider} associated with a
* {@link Call}.
*/
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 47154da..56eb7ec 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -97,6 +97,13 @@
* @param canAddCall Indicates whether an additional call can be added.
*/
public void onCanAddCallChanged(Phone phone, boolean canAddCall) { }
+
+ /**
+ * Called to silence the ringer if a ringing call exists.
+ *
+ * @param phone The {@code Phone} calling this method.
+ */
+ public void onSilenceRinger(Phone phone) { }
}
// A Map allows us to track each Call by its Telecom-specified call ID
@@ -179,6 +186,10 @@
}
}
+ final void internalSilenceRinger() {
+ fireSilenceRinger();
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
@@ -330,6 +341,12 @@
}
}
+ private void fireSilenceRinger() {
+ for (Listener listener : mListeners) {
+ listener.onSilenceRinger(this);
+ }
+ }
+
private void checkCallTree(ParcelableCall parcelableCall) {
if (parcelableCall.getParentCallId() != null &&
!mCallByTelecomCallId.containsKey(parcelableCall.getParentCallId())) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 497864e..72ff272 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -308,6 +308,15 @@
"android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
/**
+ * A boolean meta-data value indicating whether an {@link InCallService} implements ringing.
+ * Dialer implementations (see {@link #getDefaultDialerPackage()}) which would also like to
+ * override the system provided ringing should set this meta-data to {@code true} in the
+ * manifest registration of their {@link InCallService}.
+ */
+ public static final String METADATA_IN_CALL_SERVICE_RINGING =
+ "android.telecom.IN_CALL_SERVICE_RINGING";
+
+ /**
* The dual tone multi-frequency signaling character sent to indicate the dialing system should
* pause for a predefined period.
*/
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
new file mode 100644
index 0000000..2e0af27
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+/**
+ * Internal remote callback interface for call screening services.
+ *
+ * @see android.telecom.CallScreeningService
+ *
+ * {@hide}
+ */
+oneway interface ICallScreeningAdapter {
+ void allowCall(String callId);
+
+ void disallowCall(
+ String callId,
+ boolean shouldReject,
+ boolean shouldAddToCallLog,
+ boolean shouldShowNotification);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl
new file mode 100644
index 0000000..c3fe1af
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.telecom.ParcelableCall;
+
+import com.android.internal.telecom.ICallScreeningAdapter;
+
+/**
+ * Internal remote interface for a call screening service.
+ * @see android.telecom.CallScreeningService
+ * @hide
+ */
+oneway interface ICallScreeningService {
+ void screenCall(in ICallScreeningAdapter adapter, in ParcelableCall call);
+}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index ded47d5..0088e0c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -45,4 +45,6 @@
void bringToForeground(boolean showDialpad);
void onCanAddCallChanged(boolean canAddCall);
+
+ void silenceRinger();
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 630dacc..4368b81 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -409,6 +409,11 @@
public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
/**
+ * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
+ */
+ public static final String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+
+ /**
* The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
* and carrier visual voicemail are not active at the same time.
*/
@@ -638,6 +643,7 @@
sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
sDefaults.putString(KEY_VVM_TYPE_STRING, "");
sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN,false);
+ sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN,true);
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ea96e7c..84883d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -48,7 +48,9 @@
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+ if (txTimeMs != null) {
+ System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+ }
mRxTimeMs = rxTimeMs;
mEnergyUsed = energyUsed;
}
@@ -58,6 +60,7 @@
return "ModemActivityInfo{"
+ " mTimestamp=" + mTimestamp
+ " mSleepTimeMs=" + mSleepTimeMs
+ + " mIdleTimeMs=" + mIdleTimeMs
+ " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
+ " mRxTimeMs=" + mRxTimeMs
+ " mEnergyUsed=" + mEnergyUsed
@@ -153,7 +156,7 @@
for (int i = 0; i < TX_POWER_LEVELS; i++) {
totalTxTimeMs += txTime[i];
}
- return ((getIdleTimeMillis() != 0) || (totalTxTimeMs != 0)
- || (getSleepTimeMillis() != 0) || (getIdleTimeMillis() != 0));
+ return ((getIdleTimeMillis() >= 0) && (totalTxTimeMs >= 0)
+ && (getSleepTimeMillis() >= 0) && (getIdleTimeMillis() >= 0));
}
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index b089387..962a600 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1857,9 +1857,6 @@
// to the list.
number = extractNetworkPortionAlt(number);
- Rlog.d(LOG_TAG, "subId:" + subId + ", defaultCountryIso:" +
- ((defaultCountryIso == null) ? "NULL" : defaultCountryIso));
-
String emergencyNumbers = "";
int slotId = SubscriptionManager.getSlotId(subId);
@@ -1869,7 +1866,8 @@
emergencyNumbers = SystemProperties.get(ecclist, "");
- Rlog.d(LOG_TAG, "slotId:" + slotId + ", emergencyNumbers: " + emergencyNumbers);
+ Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
+ + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers);
if (TextUtils.isEmpty(emergencyNumbers)) {
// then read-only ecclist property since old RIL only uses this
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c680999..ad007c6 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -37,6 +37,7 @@
static final String LOG_TAG = "PHONE";
static final boolean DBG = true;
+ static final boolean VDBG = false; // STOPSHIP if true
/**
* Normal operation condition, the phone is registered
@@ -829,7 +830,7 @@
/** @hide */
public void setDataRegState(int state) {
mDataRegState = state;
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
+ if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
}
public void setRoaming(boolean roaming) {
@@ -1017,7 +1018,8 @@
/** @hide */
public void setRilDataRadioTechnology(int rt) {
this.mRilDataRadioTechnology = rt;
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRadioTechnology=" + mRilDataRadioTechnology);
+ if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
+ mRilDataRadioTechnology);
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
index 5dffa28..069fcbf 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -16,8 +16,9 @@
package com.android.internal.telephony;
-import android.os.Bundle;
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
+import android.os.Bundle;
/**
* Interface used to interact with the Telephony debug service.
@@ -36,4 +37,7 @@
* @param data optional
*/
void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+
+ void subscribe(in ITelephonyDebugSubscriber subscriber);
+ void unsubscribe(in ITelephonyDebugSubscriber subscriber);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
new file mode 100644
index 0000000..64eb0f1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.TelephonyEvent;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to subscribe for events from Telephony debug service.
+ *
+ * {@hide}
+ */
+oneway interface ITelephonyDebugSubscriber {
+
+ /**
+ * Called when Telephony debug service has events.
+ */
+ void onEvents(in TelephonyEvent[] events);
+}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3c4c04b..7d5645e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -336,6 +336,8 @@
int RIL_REQUEST_PULL_LCEDATA = 134;
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
+ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
+
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
new file mode 100644
index 0000000..1e74b31
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
new file mode 100644
index 0000000..26d466d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable used in ITelephonyDebugSubscriber.aidl
+ */
+public class TelephonyEvent implements Parcelable {
+
+ final public long timestamp;
+ final public int phoneId;
+ final public int tag;
+ final public int param1;
+ final public int param2;
+ final public Bundle data;
+
+ public TelephonyEvent(long timestamp, int phoneId, int tag,
+ int param1, int param2, Bundle data) {
+ this.timestamp = timestamp;
+ this.phoneId = phoneId;
+ this.tag = tag;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.data = data;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<TelephonyEvent> CREATOR
+ = new Parcelable.Creator<TelephonyEvent> (){
+ public TelephonyEvent createFromParcel(Parcel source) {
+ final long timestamp = source.readLong();
+ final int phoneId = source.readInt();
+ final int tag = source.readInt();
+ final int param1 = source.readInt();
+ final int param2 = source.readInt();
+ final Bundle data = source.readBundle();
+ return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
+ }
+
+ public TelephonyEvent[] newArray(int size) {
+ return new TelephonyEvent[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(timestamp);
+ dest.writeInt(phoneId);
+ dest.writeInt(tag);
+ dest.writeInt(param1);
+ dest.writeInt(param2);
+ dest.writeBundle(data);
+ }
+
+ public String toString() {
+ return String.format("%d,%d,%d,%d,%d,%s",
+ timestamp, phoneId, tag, param1, param2, data);
+ }
+}
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase.java b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
index a59ee35..aca1c16 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
@@ -23,15 +23,15 @@
* be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
* and you will then be able to manipulate your Activity directly. Most of the work is handled
* automatically here by {@link #setUp} and {@link #tearDown}.
- *
+ *
* <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
- *
- * @deprecated new tests should be written using
+ *
+ * @deprecated new tests should be written using
* {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
* configuring the Activity under test
*/
@Deprecated
-public abstract class ActivityInstrumentationTestCase<T extends Activity>
+public abstract class ActivityInstrumentationTestCase<T extends Activity>
extends ActivityTestCase {
String mPackage;
Class<T> mActivityClass;
@@ -39,7 +39,7 @@
/**
* Creates an {@link ActivityInstrumentationTestCase} in non-touch mode.
- *
+ *
* @param pkg ignored - no longer in use.
* @param activityClass The activity to test. This must be a class in the instrumentation
* targetPackage specified in the AndroidManifest.xml
@@ -56,7 +56,7 @@
* targetPackage specified in the AndroidManifest.xml
* @param initialTouchMode true = in touch mode
*/
- public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass,
+ public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass,
boolean initialTouchMode) {
mActivityClass = activityClass;
mInitialTouchMode = initialTouchMode;
@@ -80,8 +80,8 @@
protected void tearDown() throws Exception {
getActivity().finish();
setActivity(null);
-
- // Scrub out members - protects against memory leaks in the case where someone
+
+ // Scrub out members - protects against memory leaks in the case where someone
// creates a non-static inner class (thus referencing the test case) and gives it to
// someone else to hold onto
scrubClass(ActivityInstrumentationTestCase.class);
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
index c4bcf31..0e61ce7 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
@@ -25,26 +25,26 @@
* This class provides functional testing of a single activity. The activity under test will
* be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
* and you will then be able to manipulate your Activity directly.
- *
+ *
* <p>Other options supported by this test case include:
* <ul>
* <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li>
- * <li>You can inject custom Intents into your Activity (see
+ * <li>You can inject custom Intents into your Activity (see
* {@link #setActivityIntent(Intent)}).</li>
* </ul>
- *
+ *
* <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated.
* New tests should be written using this base class.
- *
+ *
* <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about application testing, read the
- * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
- * </div>
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
-public abstract class ActivityInstrumentationTestCase2<T extends Activity>
+@Deprecated
+public abstract class ActivityInstrumentationTestCase2<T extends Activity>
extends ActivityTestCase {
Class<T> mActivityClass;
boolean mInitialTouchMode = false;
@@ -78,18 +78,18 @@
* Get the Activity under test, starting it if necessary.
*
* For each test method invocation, the Activity will not actually be created until the first
- * time this method is called.
- *
- * <p>If you wish to provide custom setup values to your Activity, you may call
- * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)}
- * before your first call to getActivity(). Calling them after your Activity has
+ * time this method is called.
+ *
+ * <p>If you wish to provide custom setup values to your Activity, you may call
+ * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)}
+ * before your first call to getActivity(). Calling them after your Activity has
* started will have no effect.
*
* <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
* If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity
* will be started automatically just before your test method is run. You still call this
* method in order to get the Activity under test.
- *
+ *
* @return the Activity under test
*/
@Override
@@ -113,10 +113,10 @@
/**
* Call this method before the first call to {@link #getActivity} to inject a customized Intent
* into the Activity under test.
- *
+ *
* <p>If you do not call this, the default intent will be provided. If you call this after
* your Activity has been started, it will have no effect.
- *
+ *
* <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
* If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
* {@link #setActivityIntent(Intent)} from {@link #setUp()}.
@@ -131,28 +131,28 @@
public void setActivityIntent(Intent i) {
mActivityIntent = i;
}
-
+
/**
* Call this method before the first call to {@link #getActivity} to set the initial touch
* mode for the Activity under test.
- *
+ *
* <p>If you do not call this, the touch mode will be false. If you call this after
* your Activity has been started, it will have no effect.
- *
+ *
* <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
* If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
* {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}.
- *
+ *
* @param initialTouchMode true if the Activity should be placed into "touch mode" when started
*/
public void setActivityInitialTouchMode(boolean initialTouchMode) {
mInitialTouchMode = initialTouchMode;
}
-
+
@Override
protected void setUp() throws Exception {
super.setUp();
-
+
mInitialTouchMode = false;
mActivityIntent = null;
}
@@ -165,8 +165,8 @@
a.finish();
setActivity(null);
}
-
- // Scrub out members - protects against memory leaks in the case where someone
+
+ // Scrub out members - protects against memory leaks in the case where someone
// creates a non-static inner class (thus referencing the test case) and gives it to
// someone else to hold onto
scrubClass(ActivityInstrumentationTestCase2.class);
diff --git a/test-runner/src/android/test/ActivityTestCase.java b/test-runner/src/android/test/ActivityTestCase.java
index c7b1d70..51dd3ef 100644
--- a/test-runner/src/android/test/ActivityTestCase.java
+++ b/test-runner/src/android/test/ActivityTestCase.java
@@ -25,7 +25,11 @@
* This is common code used to support Activity test cases. For more useful classes, please see
* {@link android.test.ActivityUnitTestCase} and
* {@link android.test.ActivityInstrumentationTestCase}.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public abstract class ActivityTestCase extends InstrumentationTestCase {
/**
diff --git a/test-runner/src/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java
index 40cca90..a191445 100644
--- a/test-runner/src/android/test/ActivityUnitTestCase.java
+++ b/test-runner/src/android/test/ActivityUnitTestCase.java
@@ -32,14 +32,14 @@
/**
* This class provides isolated testing of a single activity. The activity under test will
- * be created with minimal connection to the system infrastructure, and you can inject mocked or
+ * be created with minimal connection to the system infrastructure, and you can inject mocked or
* wrappered versions of many of Activity's dependencies. Most of the work is handled
* automatically here by {@link #setUp} and {@link #tearDown}.
- *
+ *
* <p>If you prefer a functional test, see {@link android.test.ActivityInstrumentationTestCase}.
- *
+ *
* <p>It must be noted that, as a true unit test, your Activity will not be running in the
- * normal system and will not participate in the normal interactions with other Activities.
+ * normal system and will not participate in the normal interactions with other Activities.
* The following methods should not be called in this configuration - most of them will throw
* exceptions:
* <ul>
@@ -54,17 +54,17 @@
* <li>{@link android.app.Activity#isTaskRoot()}</li>
* <li>{@link android.app.Activity#moveTaskToBack(boolean)}</li>
* </ul>
- *
- * <p>The following methods may be called but will not do anything. For test purposes, you can use
- * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to
+ *
+ * <p>The following methods may be called but will not do anything. For test purposes, you can use
+ * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to
* inspect the parameters that they were called with.
* <ul>
* <li>{@link android.app.Activity#startActivity(Intent)}</li>
* <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li>
* </ul>
*
- * <p>The following methods may be called but will not do anything. For test purposes, you can use
- * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the
+ * <p>The following methods may be called but will not do anything. For test purposes, you can use
+ * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the
* parameters that they were called with.
* <ul>
* <li>{@link android.app.Activity#finish()}</li>
@@ -72,8 +72,12 @@
* <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
* </ul>
*
+ * @deprecated Write
+ * <a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">Local Unit Tests</a>
+ * instead.
*/
-public abstract class ActivityUnitTestCase<T extends Activity>
+@Deprecated
+public abstract class ActivityUnitTestCase<T extends Activity>
extends ActivityTestCase {
private static final String TAG = "ActivityUnitTestCase";
@@ -102,31 +106,31 @@
// default value for target context, as a default
mActivityContext = getInstrumentation().getTargetContext();
}
-
+
/**
* Start the activity under test, in the same way as if it was started by
- * {@link android.content.Context#startActivity Context.startActivity()}, providing the
+ * {@link android.content.Context#startActivity Context.startActivity()}, providing the
* arguments it supplied. When you use this method to start the activity, it will automatically
* be stopped by {@link #tearDown}.
- *
- * <p>This method will call onCreate(), but if you wish to further exercise Activity life
+ *
+ * <p>This method will call onCreate(), but if you wish to further exercise Activity life
* cycle methods, you must call them yourself from your test case.
- *
+ *
* <p><i>Do not call from your setUp() method. You must call this method from each of your
* test methods.</i>
- *
+ *
* @param intent The Intent as if supplied to {@link android.content.Context#startActivity}.
* @param savedInstanceState The instance state, if you are simulating this part of the life
* cycle. Typically null.
- * @param lastNonConfigurationInstance This Object will be available to the
- * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
+ * @param lastNonConfigurationInstance This Object will be available to the
+ * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
* Typically null.
* @return Returns the Activity that was created
*/
protected T startActivity(Intent intent, Bundle savedInstanceState,
Object lastNonConfigurationInstance) {
assertFalse("Activity already created", mCreated);
-
+
if (!mAttached) {
assertNotNull(mActivityClass);
setActivity(null);
@@ -154,7 +158,7 @@
assertNotNull(newActivity);
setActivity(newActivity);
-
+
mAttached = true;
}
@@ -165,22 +169,22 @@
}
return result;
}
-
+
@Override
protected void tearDown() throws Exception {
-
+
setActivity(null);
-
- // Scrub out members - protects against memory leaks in the case where someone
+
+ // Scrub out members - protects against memory leaks in the case where someone
// creates a non-static inner class (thus referencing the test case) and gives it to
// someone else to hold onto
scrubClass(ActivityInstrumentationTestCase.class);
super.tearDown();
}
-
+
/**
- * Set the application for use during the test. You must call this function before calling
+ * Set the application for use during the test. You must call this function before calling
* {@link #startActivity}. If your test does not call this method,
* @param application The Application object that will be injected into the Activity under test.
*/
@@ -198,7 +202,7 @@
}
/**
- * This method will return the value if your Activity under test calls
+ * This method will return the value if your Activity under test calls
* {@link android.app.Activity#setRequestedOrientation}.
*/
public int getRequestedOrientation() {
@@ -207,10 +211,10 @@
}
return 0;
}
-
+
/**
- * This method will return the launch intent if your Activity under test calls
- * {@link android.app.Activity#startActivity(Intent)} or
+ * This method will return the launch intent if your Activity under test calls
+ * {@link android.app.Activity#startActivity(Intent)} or
* {@link android.app.Activity#startActivityForResult(Intent, int)}.
* @return The Intent provided in the start call, or null if no start call was made.
*/
@@ -220,9 +224,9 @@
}
return null;
}
-
+
/**
- * This method will return the launch request code if your Activity under test calls
+ * This method will return the launch request code if your Activity under test calls
* {@link android.app.Activity#startActivityForResult(Intent, int)}.
* @return The request code provided in the start call, or -1 if no start call was made.
*/
@@ -234,9 +238,9 @@
}
/**
- * This method will notify you if the Activity under test called
- * {@link android.app.Activity#finish()},
- * {@link android.app.Activity#finishFromChild(Activity)}, or
+ * This method will notify you if the Activity under test called
+ * {@link android.app.Activity#finish()},
+ * {@link android.app.Activity#finishFromChild(Activity)}, or
* {@link android.app.Activity#finishActivity(int)}.
* @return Returns true if one of the listed finish methods was called.
*/
@@ -246,9 +250,9 @@
}
return false;
}
-
+
/**
- * This method will return the request code if the Activity under test called
+ * This method will return the request code if the Activity under test called
* {@link android.app.Activity#finishActivity(int)}.
* @return The request code provided in the start call, or -1 if no finish call was made.
*/
@@ -258,7 +262,7 @@
}
return 0;
}
-
+
/**
* This mock Activity represents the "parent" activity. By injecting this, we allow the user
* to call a few more Activity methods, including:
@@ -269,7 +273,7 @@
* <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
* <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
* </ul>
- *
+ *
* TODO: Make this overrideable, and the unit test can look for calls to other methods
*/
private static class MockParent extends Activity {
@@ -303,7 +307,7 @@
public Window getWindow() {
return null;
}
-
+
/**
* By defining this in the parent, we allow the tested activity to call
* <ul>
@@ -316,7 +320,7 @@
mStartedActivityIntent = intent;
mStartedActivityRequest = requestCode;
}
-
+
/**
* By defining this in the parent, we allow the tested activity to call
* <ul>
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index aa7c677..50eaafb 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -33,6 +33,13 @@
import java.lang.reflect.InvocationTargetException;
import java.util.List;
+/**
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
public class AndroidTestRunner extends BaseTestRunner {
private TestResult mTestResult;
diff --git a/test-runner/src/android/test/ApplicationTestCase.java b/test-runner/src/android/test/ApplicationTestCase.java
index f093181..4d73f53 100644
--- a/test-runner/src/android/test/ApplicationTestCase.java
+++ b/test-runner/src/android/test/ApplicationTestCase.java
@@ -32,7 +32,7 @@
* In order to support the lifecycle of a Application, this test case will make the
* following calls at the following times.
*
- * <ul><li>The test case will not call onCreate() until your test calls
+ * <ul><li>The test case will not call onCreate() until your test calls
* {@link #createApplication()}. This gives you a chance
* to set up or adjust any additional framework or test logic before
* onCreate().</li>
@@ -40,22 +40,28 @@
* automatically called, and it will stop & destroy your application by calling its
* onDestroy() method.</li>
* </ul>
- *
+ *
* <p><b>Dependency Injection.</b>
* Every Application has one inherent dependency, the {@link android.content.Context Context} in
* which it runs.
- * This framework allows you to inject a modified, mock, or isolated replacement for this
+ * This framework allows you to inject a modified, mock, or isolated replacement for this
* dependencies, and thus perform a true unit test.
- *
+ *
* <p>If simply run your tests as-is, your Application will be injected with a fully-functional
* Context.
- * You can create and inject alternative types of Contexts by calling
+ * You can create and inject alternative types of Contexts by calling
* {@link AndroidTestCase#setContext(Context) setContext()}. You must do this <i>before</i> calling
* {@link #createApplication()}. The test framework provides a
- * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext},
- * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and
+ * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext},
+ * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and
* {@link android.content.ContextWrapper ContextWrapper}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public abstract class ApplicationTestCase<T extends Application> extends AndroidTestCase {
Class<T> mApplicationClass;
@@ -78,17 +84,17 @@
}
/**
- * This will do the work to instantiate the Application under test. After this, your test
+ * This will do the work to instantiate the Application under test. After this, your test
* code must also start and stop the Application.
*/
@Override
protected void setUp() throws Exception {
super.setUp();
-
+
// get the real context, before the individual tests have a chance to muck with it
mSystemContext = getContext();
}
-
+
/**
* Load and attach the application under test.
*/
@@ -101,26 +107,26 @@
}
mAttached = true;
}
-
+
/**
- * Start the Application under test, in the same way as if it was started by the system.
+ * Start the Application under test, in the same way as if it was started by the system.
* If you use this method to start the Application, it will automatically
* be stopped by {@link #tearDown}. If you wish to inject a specialized Context for your
- * test, by calling {@link AndroidTestCase#setContext(Context) setContext()},
+ * test, by calling {@link AndroidTestCase#setContext(Context) setContext()},
* you must do so before calling this method.
*/
final protected void createApplication() {
assertFalse(mCreated);
-
+
if (!mAttached) {
setupApplication();
}
assertNotNull(mApplication);
-
+
mApplication.onCreate();
mCreated = true;
}
-
+
/**
* This will make the necessary calls to terminate the Application under test (it will
* call onTerminate(). Ordinarily this will be called automatically (by {@link #tearDown}, but
@@ -131,13 +137,13 @@
mApplication.onTerminate();
}
}
-
+
/**
- * Shuts down the Application under test. Also makes sure all resources are cleaned up and
+ * Shuts down the Application under test. Also makes sure all resources are cleaned up and
* garbage collected before moving on to the next
* test. Subclasses that override this method should make sure they call super.tearDown()
* at the end of the overriding method.
- *
+ *
* @throws Exception
*/
@Override
@@ -145,7 +151,7 @@
terminateApplication();
mApplication = null;
- // Scrub out members - protects against memory leaks in the case where someone
+ // Scrub out members - protects against memory leaks in the case where someone
// creates a non-static inner class (thus referencing the test case) and gives it to
// someone else to hold onto
scrubClass(ApplicationTestCase.class);
@@ -156,7 +162,7 @@
/**
* Return a real (not mocked or instrumented) system Context that can be used when generating
* Mock or other Context objects for your Application under test.
- *
+ *
* @return Returns a reference to a normal Context.
*/
public Context getSystemContext() {
@@ -165,7 +171,7 @@
/**
* This test simply confirms that the Application class can be instantiated properly.
- *
+ *
* @throws Exception
*/
final public void testApplicationTestCaseSetUpProperly() throws Exception {
diff --git a/test-runner/src/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java
index b3ac6d1..fc3e98e 100644
--- a/test-runner/src/android/test/AssertionFailedError.java
+++ b/test-runner/src/android/test/AssertionFailedError.java
@@ -18,17 +18,18 @@
/**
* Thrown when an assertion failed.
- *
+ *
* @deprecated use junit.framework.AssertionFailedError
*/
+@Deprecated
public class AssertionFailedError extends Error {
-
+
/**
* It is more typical to call {@link #AssertionFailedError(String)}.
*/
public AssertionFailedError() {
}
-
+
public AssertionFailedError(String errorMessage) {
super(errorMessage);
}
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
index 1f6e647..1ab7c7f 100644
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ b/test-runner/src/android/test/ClassPathPackageInfo.java
@@ -24,9 +24,10 @@
/**
* The Package object doesn't allow you to iterate over the contained
* classes and subpackages of that package. This is a version that does.
- *
+ *
* {@hide} Not needed for 1.0 SDK.
*/
+@Deprecated
public class ClassPathPackageInfo {
private final ClassPathPackageInfoSource source;
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 0ffecdb..89bb494 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -33,9 +33,10 @@
/**
* Generate {@link ClassPathPackageInfo}s by scanning apk paths.
- *
+ *
* {@hide} Not needed for 1.0 SDK.
*/
+@Deprecated
public class ClassPathPackageInfoSource {
private static final String CLASS_EXTENSION = ".class";
@@ -82,7 +83,7 @@
// Don't try to load classes that are generated. They usually aren't in test apks.
continue;
}
-
+
try {
// We get errors in the emulator if we don't use the caller's class loader.
topLevelClasses.add(Class.forName(className, false,
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
index 23e0aba..42ef48b 100644
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ b/test-runner/src/android/test/DatabaseTestUtils.java
@@ -27,6 +27,7 @@
* A collection of utilities for writing unit tests for database code.
* @hide pending API council approval
*/
+@Deprecated
public class DatabaseTestUtils {
/**
diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
index 655a65c..2b05e4a 100644
--- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
@@ -41,6 +41,7 @@
*
* @hide
*/
+@Deprecated
public class InstrumentationCoreTestRunner extends InstrumentationTestRunner {
/**
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index db80ef951..9bd4c96 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -155,6 +155,10 @@
* -e coverageFile /sdcard/myFile.ec
* <br/>
* in addition to the other arguments.
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
/* (not JavaDoc)
@@ -170,6 +174,7 @@
*
* This model is used by many existing app tests, but can probably be deprecated.
*/
+@Deprecated
public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
/** @hide */
diff --git a/test-runner/src/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java
index 1a7002a..cc50813 100644
--- a/test-runner/src/android/test/InstrumentationUtils.java
+++ b/test-runner/src/android/test/InstrumentationUtils.java
@@ -17,17 +17,17 @@
package android.test;
/**
- *
* The InstrumentationUtils class has all the utility functions needed for
* instrumentation tests.
*
* {@hide} - Not currently used.
*/
+@Deprecated
public class InstrumentationUtils {
/**
* An utility function that returns the menu identifier for a particular
* menu item.
- *
+ *
* @param cls Class object of the class that handles the menu ite,.
* @param identifier Menu identifier.
* @return The integer corresponding to the menu item.
@@ -35,7 +35,7 @@
public static int getMenuIdentifier(Class cls, String identifier) {
int id = -1;
try {
- Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);
+ Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);
id = field.intValue();
} catch (NoSuchFieldException e) {
e.printStackTrace();
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index f971b5d..3abf38f 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -43,9 +43,13 @@
/**
- * A mock context which prevents its users from talking to the rest of the device while
+ * A mock context which prevents its users from talking to the rest of the device while
* stubbing enough methods to satify code that tries to talk to other packages.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class IsolatedContext extends ContextWrapper {
private ContentResolver mResolver;
diff --git a/test-runner/src/android/test/LaunchPerformanceBase.java b/test-runner/src/android/test/LaunchPerformanceBase.java
index d423e62..62c90d6 100644
--- a/test-runner/src/android/test/LaunchPerformanceBase.java
+++ b/test-runner/src/android/test/LaunchPerformanceBase.java
@@ -26,6 +26,7 @@
*
* @hide
*/
+@Deprecated
public class LaunchPerformanceBase extends Instrumentation {
public static final String LOG_TAG = "Launch Performance";
@@ -39,7 +40,7 @@
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setAutomaticPerformanceSnapshots();
}
-
+
/**
* Launches intent, and waits for idle before returning.
*
diff --git a/test-runner/src/android/test/MoreAsserts.java b/test-runner/src/android/test/MoreAsserts.java
index 3364895..d33911a 100644
--- a/test-runner/src/android/test/MoreAsserts.java
+++ b/test-runner/src/android/test/MoreAsserts.java
@@ -30,7 +30,10 @@
/**
* Contains additional assertion methods not found in JUnit.
+ * @deprecated Use
+ * <a href="https://github.com/hamcrest">Hamcrest matchers</a> instead.
*/
+@Deprecated
public final class MoreAsserts {
private MoreAsserts() { }
@@ -375,7 +378,7 @@
failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")");
}
}
-
+
if (expectedMap.size() > 0) {
failWithMessage(message, "Extra objects in expected.");
}
diff --git a/test-runner/src/android/test/NoExecTestResult.java b/test-runner/src/android/test/NoExecTestResult.java
index 1ee62c1..a01b6aa 100644
--- a/test-runner/src/android/test/NoExecTestResult.java
+++ b/test-runner/src/android/test/NoExecTestResult.java
@@ -19,11 +19,12 @@
import junit.framework.TestResult;
/**
- * A benign test result that does no actually test execution, just runs
+ * A benign test result that does no actually test execution, just runs
* through the motions
- *
+ *
* {@hide} Not needed for SDK.
*/
+@Deprecated
class NoExecTestResult extends TestResult {
/**
diff --git a/test-runner/src/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java
index ef37449..205f86b 100644
--- a/test-runner/src/android/test/PackageInfoSources.java
+++ b/test-runner/src/android/test/PackageInfoSources.java
@@ -19,6 +19,7 @@
/**
* {@hide} Not needed for SDK.
*/
+@Deprecated
public class PackageInfoSources {
private static ClassPathPackageInfoSource classPathSource;
diff --git a/test-runner/src/android/test/PerformanceCollectorTestCase.java b/test-runner/src/android/test/PerformanceCollectorTestCase.java
index 4309ff7..3a5dafc 100644
--- a/test-runner/src/android/test/PerformanceCollectorTestCase.java
+++ b/test-runner/src/android/test/PerformanceCollectorTestCase.java
@@ -30,6 +30,7 @@
*
* {@hide} Not needed for SDK.
*/
+@Deprecated
public interface PerformanceCollectorTestCase {
public PerformanceCollector mPerfCollector = new PerformanceCollector();
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 3c4da9e..36786b0 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -36,7 +36,11 @@
* This is a class which delegates to the given context, but performs database
* and file operations with a renamed database/file name (prefixes default
* names with a given prefix).
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class RenamingDelegatingContext extends ContextWrapper {
private Context mFileContext;
@@ -168,7 +172,7 @@
return false;
}
}
-
+
@Override
public File getDatabasePath(String name) {
return mFileContext.getDatabasePath(renamedFileName(name));
@@ -216,7 +220,7 @@
public String[] fileList() {
return mFileNames.toArray(new String[]{});
}
-
+
/**
* In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
* one) and return it instead. This code is basically getCacheDir(), except it uses the real
@@ -241,21 +245,4 @@
}
return mCacheDir;
}
-
-
-// /**
-// * Given an array of files returns only those whose names indicate that they belong to this
-// * context.
-// * @param allFiles the original list of files
-// * @return the pruned list of files
-// */
-// private String[] prunedFileList(String[] allFiles) {
-// List<String> files = Lists.newArrayList();
-// for (String file : allFiles) {
-// if (file.startsWith(mFilePrefix)) {
-// files.add(file);
-// }
-// }
-// return files.toArray(new String[]{});
-// }
}
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index ba20c09..c8ff0f9 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -92,7 +92,13 @@
* {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
* {@link android.content.ContextWrapper ContextWrapper}, and
* {@link android.test.IsolatedContext}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">
+ * ServiceTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
Class<T> mServiceClass;
diff --git a/test-runner/src/android/test/SimpleCache.java b/test-runner/src/android/test/SimpleCache.java
index 44424ec..46143e4 100644
--- a/test-runner/src/android/test/SimpleCache.java
+++ b/test-runner/src/android/test/SimpleCache.java
@@ -19,6 +19,7 @@
import java.util.HashMap;
import java.util.Map;
+@Deprecated
abstract class SimpleCache<K, V> {
private Map<K, V> map = new HashMap<K, V>();
diff --git a/test-runner/src/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
index 72c93ce..af1448e 100644
--- a/test-runner/src/android/test/SingleLaunchActivityTestCase.java
+++ b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
@@ -22,13 +22,19 @@
* If you would like to test a single activity with an
* {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate to
* launch and finish the activity in {@link #setUp} and {@link #tearDown}.
- *
- * This launches the activity only once for the entire class instead of doing it
+ *
+ * This launches the activity only once for the entire class instead of doing it
* in every setup / teardown call.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public abstract class SingleLaunchActivityTestCase<T extends Activity>
extends InstrumentationTestCase {
-
+
String mPackage;
Class<T> mActivityClass;
private static int sTestCaseCounter = 0;
@@ -44,10 +50,10 @@
*/
public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) {
mPackage = pkg;
- mActivityClass = activityClass;
- sTestCaseCounter ++;
+ mActivityClass = activityClass;
+ sTestCaseCounter ++;
}
-
+
/**
* The activity that will be set up for use in each test method.
*/
@@ -66,7 +72,7 @@
getInstrumentation().setInTouchMode(false);
sActivity = launchActivity(mPackage, mActivityClass, null);
sActivityLaunchedFlag = true;
- }
+ }
}
@Override
@@ -75,7 +81,7 @@
sTestCaseCounter --;
if (sTestCaseCounter == 0) {
sActivity.finish();
- }
+ }
super.tearDown();
}
diff --git a/test-runner/src/android/test/SyncBaseInstrumentation.java b/test-runner/src/android/test/SyncBaseInstrumentation.java
index 7d418f0..de36b4f 100644
--- a/test-runner/src/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/src/android/test/SyncBaseInstrumentation.java
@@ -27,7 +27,13 @@
* If you would like to test sync a single provider with an
* {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and
* {@link #tearDown}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class SyncBaseInstrumentation extends InstrumentationTestCase {
private Context mTargetContext;
ContentResolver mContentResolver;
diff --git a/test-runner/src/android/test/TestCase.java b/test-runner/src/android/test/TestCase.java
index 5432ce8..b234f44 100644
--- a/test-runner/src/android/test/TestCase.java
+++ b/test-runner/src/android/test/TestCase.java
@@ -23,14 +23,13 @@
* More complex interface for test cases.
*
* <p>Just implementing Runnable is enough for many test cases. If you
- * have additional setup or teardown, this interface might be for you,
+ * have additional setup or teardown, this interface might be for you,
* especially if you need to share it between different test cases, or your
* teardown code must execute regardless of whether your test passed.
*
* <p>See the android.test package documentation (click the more... link)
* for a full description
*/
-
@Deprecated
public interface TestCase extends Runnable
{
diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
index 3ba9711..c46d403 100644
--- a/test-runner/src/android/test/TestCaseUtil.java
+++ b/test-runner/src/android/test/TestCaseUtil.java
@@ -35,6 +35,7 @@
* @hide - This is part of a framework that is under development and should not be used for
* active development.
*/
+@Deprecated
public class TestCaseUtil {
private TestCaseUtil() {
@@ -67,7 +68,7 @@
*/
if (test instanceof TestCase &&
((TestCase)test).getName() == null) {
- workingTest = invokeSuiteMethodIfPossible(test.getClass(),
+ workingTest = invokeSuiteMethodIfPossible(test.getClass(),
seen);
}
if (workingTest == null) {
@@ -155,7 +156,7 @@
public static TestSuite createTestSuite(Class<? extends Test> testClass)
throws InstantiationException, IllegalAccessException {
- Test test = invokeSuiteMethodIfPossible(testClass,
+ Test test = invokeSuiteMethodIfPossible(testClass,
new HashSet<Class<?>>());
if (test == null) {
return new TestSuite(testClass);
diff --git a/test-runner/src/android/test/TestPrinter.java b/test-runner/src/android/test/TestPrinter.java
index 37bd721..a23f06d 100644
--- a/test-runner/src/android/test/TestPrinter.java
+++ b/test-runner/src/android/test/TestPrinter.java
@@ -30,9 +30,10 @@
* probably will not need to create or extend this class or call its methods manually.
* See the full {@link android.test} package description for information about
* getting test results.
- *
+ *
* {@hide} Not needed for 1.0 SDK.
*/
+@Deprecated
public class TestPrinter implements TestRunner.Listener, TestListener {
private String mTag;
@@ -89,7 +90,7 @@
mFailedTests.add(test.toString());
failed(test.toString(), t);
}
-
+
public void addError(Test test, Throwable t) {
failed(test, t);
}
diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
index 012df35..beecc6f 100644
--- a/test-runner/src/android/test/TestRunner.java
+++ b/test-runner/src/android/test/TestRunner.java
@@ -42,6 +42,7 @@
*
* {@hide} Not needed for 1.0 SDK.
*/
+@Deprecated
public class TestRunner implements PerformanceTestCase.Intermediates {
public static final int REGRESSION = 0;
public static final int PERFORMANCE = 1;
diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java
index dc9ce6e..c74651c 100644
--- a/test-runner/src/android/test/TestSuiteProvider.java
+++ b/test-runner/src/android/test/TestSuiteProvider.java
@@ -21,6 +21,7 @@
/**
* Implementors will know how to get a test suite.
*/
+@Deprecated
public interface TestSuiteProvider {
TestSuite getTestSuite();
diff --git a/test-runner/src/android/test/TimedTest.java b/test-runner/src/android/test/TimedTest.java
index 95cc9bf..cb15ef9 100644
--- a/test-runner/src/android/test/TimedTest.java
+++ b/test-runner/src/android/test/TimedTest.java
@@ -30,6 +30,7 @@
*
* {@hide} Pending approval for public API.
*/
+@Deprecated
@Retention(RetentionPolicy.RUNTIME)
public @interface TimedTest {
boolean includeDetailedStats() default false;
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index 1b854b0..28dc7b2 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -31,9 +31,15 @@
* Reusable methods for generating touch events. These methods can be used with
* InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with
* the application through a touch screen.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso UI testing
+ * framework</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TouchUtils {
-
+
/**
* Simulate touching in the center of the screen and dragging one quarter of the way down
* @param test The test case that is being run
@@ -46,7 +52,7 @@
public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
dragQuarterScreenDown(test, test.getActivity());
}
-
+
/**
* Simulate touching in the center of the screen and dragging one quarter of the way down
* @param test The test case that is being run
@@ -56,14 +62,14 @@
Display display = activity.getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
-
+
final float x = size.x / 2.0f;
final float fromY = size.y * 0.5f;
final float toY = size.y * 0.75f;
-
+
drag(test, x, x, fromY, toY, 4);
}
-
+
/**
* Simulate touching in the center of the screen and dragging one quarter of the way up
* @param test The test case that is being run
@@ -76,7 +82,7 @@
public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
dragQuarterScreenUp(test, test.getActivity());
}
-
+
/**
* Simulate touching in the center of the screen and dragging one quarter of the way up
* @param test The test case that is being run
@@ -86,18 +92,18 @@
Display display = activity.getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
-
+
final float x = size.x / 2.0f;
final float fromY = size.y * 0.5f;
final float toY = size.y * 0.25f;
-
+
drag(test, x, x, fromY, toY, 4);
}
-
+
/**
* Scroll a ViewGroup to the bottom by repeatedly calling
* {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
- *
+ *
* @param test The test case that is being run
* @param v The ViewGroup that should be dragged
*
@@ -109,11 +115,11 @@
public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
scrollToBottom(test, test.getActivity(), v);
}
-
+
/**
* Scroll a ViewGroup to the bottom by repeatedly calling
* {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
- *
+ *
* @param test The test case that is being run
* @param activity The activity that is in the foreground of the test case
* @param v The ViewGroup that should be dragged
@@ -132,7 +138,7 @@
/**
* Scroll a ViewGroup to the top by repeatedly calling
* {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
- *
+ *
* @param test The test case that is being run
* @param v The ViewGroup that should be dragged
*
@@ -144,11 +150,11 @@
public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
scrollToTop(test, test.getActivity(), v);
}
-
+
/**
* Scroll a ViewGroup to the top by repeatedly calling
* {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
- *
+ *
* @param test The test case that is being run
* @param activity The activity that is in the foreground of the test case
* @param v The ViewGroup that should be dragged
@@ -162,10 +168,10 @@
next = new ViewStateSnapshot(v);
} while (!prev.equals(next));
}
-
+
/**
* Simulate touching the center of a view and dragging to the bottom of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
*
@@ -177,10 +183,10 @@
public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
dragViewToBottom(test, test.getActivity(), v, 4);
}
-
+
/**
* Simulate touching the center of a view and dragging to the bottom of the screen.
- *
+ *
* @param test The test case that is being run
* @param activity The activity that is in the foreground of the test case
* @param v The view that should be dragged
@@ -188,10 +194,10 @@
public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) {
dragViewToBottom(test, activity, v, 4);
}
-
+
/**
* Simulate touching the center of a view and dragging to the bottom of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param stepCount How many move steps to include in the drag
@@ -205,10 +211,10 @@
int stepCount) {
dragViewToBottom(test, test.getActivity(), v, stepCount);
}
-
+
/**
* Simulate touching the center of a view and dragging to the bottom of the screen.
- *
+ *
* @param test The test case that is being run
* @param activity The activity that is in the foreground of the test case
* @param v The view that should be dragged
@@ -220,38 +226,38 @@
int[] xy = new int[2];
v.getLocationOnScreen(xy);
-
+
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
final float x = xy[0] + (viewWidth / 2.0f);
float fromY = xy[1] + (viewHeight / 2.0f);
float toY = screenHeight - 1;
-
+
drag(test, x, x, fromY, toY, stepCount);
}
/**
* Simulate touching the center of a view and releasing quickly (before the tap timeout).
- *
+ *
* @param test The test case that is being run
* @param v The view that should be clicked
*/
public static void tapView(InstrumentationTestCase test, View v) {
int[] xy = new int[2];
v.getLocationOnScreen(xy);
-
+
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
final float x = xy[0] + (viewWidth / 2.0f);
float y = xy[1] + (viewHeight / 2.0f);
-
+
Instrumentation inst = test.getInstrumentation();
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
-
+
MotionEvent event = MotionEvent.obtain(downTime, eventTime,
MotionEvent.ACTION_DOWN, x, y, 0);
inst.sendPointerSync(event);
@@ -308,30 +314,30 @@
/**
* Simulate touching the center of a view and releasing.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be clicked
*/
public static void clickView(InstrumentationTestCase test, View v) {
int[] xy = new int[2];
v.getLocationOnScreen(xy);
-
+
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
final float x = xy[0] + (viewWidth / 2.0f);
float y = xy[1] + (viewHeight / 2.0f);
-
+
Instrumentation inst = test.getInstrumentation();
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
-
+
MotionEvent event = MotionEvent.obtain(downTime, eventTime,
MotionEvent.ACTION_DOWN, x, y, 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
-
+
eventTime = SystemClock.uptimeMillis();
final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
@@ -344,7 +350,7 @@
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
-
+
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
@@ -354,7 +360,7 @@
/**
* Simulate touching the center of a view, holding until it is a long press, and then releasing.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be clicked
*
@@ -369,20 +375,20 @@
/**
* Simulate touching the center of a view, holding until it is a long press, and then releasing.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be clicked
*/
public static void longClickView(InstrumentationTestCase test, View v) {
int[] xy = new int[2];
v.getLocationOnScreen(xy);
-
+
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
final float x = xy[0] + (viewWidth / 2.0f);
float y = xy[1] + (viewHeight / 2.0f);
-
+
Instrumentation inst = test.getInstrumentation();
long downTime = SystemClock.uptimeMillis();
@@ -399,7 +405,7 @@
x + touchSlop / 2, y + touchSlop / 2, 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
-
+
try {
Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
} catch (InterruptedException e) {
@@ -414,7 +420,7 @@
/**
* Simulate touching the center of a view and dragging to the top of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
*
@@ -426,10 +432,10 @@
public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
dragViewToTop((InstrumentationTestCase) test, v, 4);
}
-
+
/**
* Simulate touching the center of a view and dragging to the top of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param stepCount How many move steps to include in the drag
@@ -442,20 +448,20 @@
public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
dragViewToTop((InstrumentationTestCase) test, v, stepCount);
}
-
+
/**
* Simulate touching the center of a view and dragging to the top of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
*/
public static void dragViewToTop(InstrumentationTestCase test, View v) {
dragViewToTop(test, v, 4);
}
-
+
/**
* Simulate touching the center of a view and dragging to the top of the screen.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param stepCount How many move steps to include in the drag
@@ -463,21 +469,21 @@
public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) {
int[] xy = new int[2];
v.getLocationOnScreen(xy);
-
+
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
final float x = xy[0] + (viewWidth / 2.0f);
float fromY = xy[1] + (viewHeight / 2.0f);
float toY = 0;
-
+
drag(test, x, x, fromY, toY, stepCount);
}
-
+
/**
* Get the location of a view. Use the gravity param to specify which part of the view to
* return.
- *
+ *
* @param v View to find
* @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
* RIGHT)
@@ -488,7 +494,7 @@
final int viewWidth = v.getWidth();
final int viewHeight = v.getHeight();
-
+
switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
break;
@@ -501,7 +507,7 @@
default:
// Same as top -- do nothing
}
-
+
switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
break;
@@ -518,14 +524,14 @@
/**
* Simulate touching a view and dragging it by the specified amount.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param deltaX Amount to drag horizontally in pixels
* @param deltaY Amount to drag vertically in pixels
- *
+ *
* @return distance in pixels covered by the drag
*
* @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -537,17 +543,17 @@
int deltaX, int deltaY) {
return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY);
}
-
+
/**
* Simulate touching a view and dragging it by the specified amount.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param deltaX Amount to drag horizontally in pixels
* @param deltaY Amount to drag vertically in pixels
- *
+ *
* @return distance in pixels covered by the drag
*
* @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -558,29 +564,29 @@
public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
int deltaY) {
int[] xy = new int[2];
-
+
getStartLocation(v, gravity, xy);
final int fromX = xy[0];
final int fromY = xy[1];
-
+
int distance = (int) Math.hypot(deltaX, deltaY);
drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
return distance;
}
-
+
/**
* Simulate touching a view and dragging it to a specified location.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toX Final location of the view after dragging
* @param toY Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*
* @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -595,14 +601,14 @@
/**
* Simulate touching a view and dragging it to a specified location.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toX Final location of the view after dragging
* @param toY Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*/
public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX,
@@ -610,28 +616,28 @@
int[] xy = new int[2];
getStartLocation(v, gravity, xy);
-
+
final int fromX = xy[0];
final int fromY = xy[1];
-
+
int deltaX = fromX - toX;
int deltaY = fromY - toY;
-
+
int distance = (int)Math.hypot(deltaX, deltaY);
drag(test, fromX, toX, fromY, toY, distance);
-
+
return distance;
}
/**
* Simulate touching a view and dragging it to a specified location. Only moves horizontally.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toX Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*
* @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -646,39 +652,39 @@
/**
* Simulate touching a view and dragging it to a specified location. Only moves horizontally.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toX Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*/
public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) {
int[] xy = new int[2];
getStartLocation(v, gravity, xy);
-
+
final int fromX = xy[0];
final int fromY = xy[1];
-
+
int deltaX = fromX - toX;
drag(test, fromX, toX, fromY, fromY, deltaX);
-
+
return deltaX;
}
-
+
/**
* Simulate touching a view and dragging it to a specified location. Only moves vertically.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toY Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*
* @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -690,37 +696,37 @@
int toY) {
return dragViewToY((InstrumentationTestCase) test, v, gravity, toY);
}
-
+
/**
* Simulate touching a view and dragging it to a specified location. Only moves vertically.
- *
+ *
* @param test The test case that is being run
* @param v The view that should be dragged
* @param gravity Which part of the view to use for the initial down event. A combination of
* (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
* @param toY Final location of the view after dragging
- *
+ *
* @return distance in pixels covered by the drag
*/
public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) {
int[] xy = new int[2];
getStartLocation(v, gravity, xy);
-
+
final int fromX = xy[0];
final int fromY = xy[1];
-
+
int deltaY = fromY - toY;
drag(test, fromX, fromX, fromY, toY, deltaY);
-
+
return deltaY;
}
-
+
/**
* Simulate touching a specific location and dragging to a new location.
- *
+ *
* @param test The test case that is being run
* @param fromX X coordinate of the initial touch, in screen coordinates
* @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -737,10 +743,10 @@
float fromY, float toY, int stepCount) {
drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount);
}
-
+
/**
* Simulate touching a specific location and dragging to a new location.
- *
+ *
* @param test The test case that is being run
* @param fromX X coordinate of the initial touch, in screen coordinates
* @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -757,7 +763,7 @@
float y = fromY;
float x = fromX;
-
+
float yStep = (toY - fromY) / stepCount;
float xStep = (toX - fromX) / stepCount;
diff --git a/test-runner/src/android/test/ViewAsserts.java b/test-runner/src/android/test/ViewAsserts.java
index c575fc5..00ab443 100644
--- a/test-runner/src/android/test/ViewAsserts.java
+++ b/test-runner/src/android/test/ViewAsserts.java
@@ -23,7 +23,15 @@
/**
* Some useful assertions about views.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">Espresso
+ * View Matchers</a> instead. New test should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * For more information about UI testing, take the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Espresso UI testing</a> training.
*/
+@Deprecated
public class ViewAsserts {
private ViewAsserts() {}
diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-runner/src/android/test/mock/MockApplication.java
index 572dfbf..3257ecf 100644
--- a/test-runner/src/android/test/mock/MockApplication.java
+++ b/test-runner/src/android/test/mock/MockApplication.java
@@ -20,12 +20,17 @@
import android.content.res.Configuration;
/**
- * A mock {@link android.app.Application} class. All methods are non-functional and throw
- * {@link java.lang.UnsupportedOperationException}. Override it as necessary to provide the
+ * A mock {@link android.app.Application} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it as necessary to provide the
* operations that you need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockApplication extends Application {
-
+
public MockApplication() {
}
@@ -38,7 +43,7 @@
public void onTerminate() {
throw new UnsupportedOperationException();
}
-
+
@Override
public void onConfigurationChanged(Configuration newConfig) {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 5ef71df..3743fb0 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -41,7 +41,12 @@
* Mock implementation of ContentProvider. All methods are non-functional and throw
* {@link java.lang.UnsupportedOperationException}. Tests can extend this class to
* implement behavior needed for tests.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockContentProvider extends ContentProvider {
/*
* Note: if you add methods to ContentProvider, you must add similar methods to
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index aec6c77..75c8335 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -49,8 +49,12 @@
* <p>For more information about application testing, read the
* <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
* </div>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
-
+@Deprecated
public class MockContentResolver extends ContentResolver {
Map<String, ContentProvider> mProviders;
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 64d2978..9b93bda 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -52,10 +52,15 @@
import java.io.InputStream;
/**
- * A mock {@link android.content.Context} class. All methods are non-functional and throw
+ * A mock {@link android.content.Context} class. All methods are non-functional and throw
* {@link java.lang.UnsupportedOperationException}. You can use this to inject other dependencies,
* mocks, or monitors into the classes you are testing.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockContext extends Context {
@Override
@@ -82,12 +87,12 @@
public Looper getMainLooper() {
throw new UnsupportedOperationException();
}
-
+
@Override
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
-
+
@Override
public void setTheme(int resid) {
throw new UnsupportedOperationException();
@@ -124,7 +129,7 @@
public ApplicationInfo getApplicationInfo() {
throw new UnsupportedOperationException();
}
-
+
@Override
public String getPackageResourcePath() {
throw new UnsupportedOperationException();
@@ -194,7 +199,7 @@
public File getObbDir() {
throw new UnsupportedOperationException();
}
-
+
@Override
public File getCacheDir() {
throw new UnsupportedOperationException();
@@ -216,7 +221,7 @@
}
@Override
- public SQLiteDatabase openOrCreateDatabase(String file, int mode,
+ public SQLiteDatabase openOrCreateDatabase(String file, int mode,
SQLiteDatabase.CursorFactory factory) {
throw new UnsupportedOperationException();
}
@@ -310,7 +315,7 @@
Bundle options) throws IntentSender.SendIntentException {
startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags);
}
-
+
@Override
public void sendBroadcast(Intent intent) {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index 28fa0f8..576f24a 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -25,15 +25,18 @@
import android.os.Bundle;
/**
- * <P>
* A mock {@link android.database.Cursor} class that isolates the test code from real
* Cursor implementation.
- * </P>
- * <P>
+ *
+ * <p>
* All methods including ones related to querying the state of the cursor are
* are non-functional and throw {@link java.lang.UnsupportedOperationException}.
- * </P>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockCursor implements Cursor {
@Override
public int getColumnCount() {
diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-runner/src/android/test/mock/MockDialogInterface.java
index e4dd0ba..d0a5a09 100644
--- a/test-runner/src/android/test/mock/MockDialogInterface.java
+++ b/test-runner/src/android/test/mock/MockDialogInterface.java
@@ -1,14 +1,33 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * Copyright (C) 2008 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.test.mock;
import android.content.DialogInterface;
/**
- * A mock {@link android.content.DialogInterface} class. All methods are non-functional and throw
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
+ * A mock {@link android.content.DialogInterface} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
* need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockDialogInterface implements DialogInterface {
public void cancel() {
throw new UnsupportedOperationException("not implemented yet");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 5296d4d..ffb73f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -60,7 +60,12 @@
* A mock {@link android.content.pm.PackageManager} class. All methods are non-functional and throw
* {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
* need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockPackageManager extends PackageManager {
@Override
diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-runner/src/android/test/mock/MockResources.java
index 18752ce..880343e 100644
--- a/test-runner/src/android/test/mock/MockResources.java
+++ b/test-runner/src/android/test/mock/MockResources.java
@@ -32,10 +32,15 @@
import java.io.InputStream;
/**
- * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
+ * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
* need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class MockResources extends Resources {
public MockResources() {
diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk
new file mode 100644
index 0000000..7bcab5e
--- /dev/null
+++ b/tests/SoundTriggerTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SoundTriggerTestApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..40619da
--- /dev/null
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.soundtrigger">
+
+ <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+ <application
+ android:permission="android.permission.MANAGE_SOUND_TRIGGER">
+ <activity
+ android:name="TestSoundTriggerActivity"
+ android:label="SoundTrigger Test Application"
+ android:theme="@android:style/Theme.Material.Light.Voice">
+ <intent-filter>
+ <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
new file mode 100644
index 0000000..9d2b9d9
--- /dev/null
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 Google Inc.
+
+ 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/enroll"
+ android:onClick="onEnrollButtonClicked"
+ android:padding="20dp" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/reenroll"
+ android:onClick="onReEnrollButtonClicked"
+ android:padding="20dp" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/unenroll"
+ android:onClick="onUnEnrollButtonClicked"
+ android:padding="20dp" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
similarity index 70%
copy from packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
copy to tests/SoundTriggerTestApp/res/values/strings.xml
index 745af33..07bac2a 100644
--- a/packages/SystemUI/res/drawable/recents_task_view_header_bg.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,8 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@android:color/transparent" />
-</ripple>
\ No newline at end of file
+ <string name="enroll">Enroll</string>
+ <string name="reenroll">Re-enroll</string>
+ <string name="unenroll">Un-enroll</string>
+</resources>
\ No newline at end of file
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
new file mode 100644
index 0000000..4702835
--- /dev/null
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.soundtrigger;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.UUID;
+
+/**
+ * Utility class for the managing sound trigger sound models.
+ */
+public class SoundTriggerUtil {
+ private static final String TAG = "TestSoundTriggerUtil:Hotsound";
+
+ private final ISoundTriggerService mSoundTriggerService;
+ private final SoundTriggerManager mSoundTriggerManager;
+ private final Context mContext;
+
+ public SoundTriggerUtil(Context context) {
+ mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+ ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+ mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+ Context.SOUND_TRIGGER_SERVICE);
+ mContext = context;
+ }
+
+ /**
+ * Adds/Updates a sound model.
+ * The sound model must contain a valid UUID.
+ *
+ * @param soundModel The sound model to add/update.
+ */
+ public boolean addOrUpdateSoundModel(GenericSoundModel soundModel) {
+ try {
+ mSoundTriggerService.updateSoundModel(soundModel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in updateSoundModel", e);
+ }
+ return true;
+ }
+
+ public void addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
+ mSoundTriggerManager.updateModel(soundModel);
+ }
+
+ /**
+ * Gets the sound model for the given keyphrase, null if none exists.
+ * If a sound model for a given keyphrase exists, and it needs to be updated,
+ * it should be obtained using this method, updated and then passed in to
+ * {@link #addOrUpdateSoundModel(GenericSoundModel)} without changing the IDs.
+ *
+ * @param modelId The model ID to look-up the sound model for.
+ * @return The sound model if one was found, null otherwise.
+ */
+ @Nullable
+ public GenericSoundModel getSoundModel(UUID modelId) {
+ GenericSoundModel model = null;
+ try {
+ model = mSoundTriggerService.getSoundModel(new ParcelUuid(modelId));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
+ }
+
+ if (model == null) {
+ Log.w(TAG, "No models present for the gien keyphrase ID");
+ return null;
+ } else {
+ return model;
+ }
+ }
+
+ /**
+ * Deletes the sound model for the given keyphrase id.
+ *
+ * @param modelId The model ID to look-up the sound model for.
+ * @return {@code true} if the call succeeds, {@code false} otherwise.
+ */
+ @Nullable
+ public boolean deleteSoundModel(UUID modelId) {
+ try {
+ mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelId));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in updateSoundModel");
+ }
+ return true;
+ }
+
+ public void deleteSoundModelUsingManager(UUID modelId) {
+ mSoundTriggerManager.deleteModel(modelId);
+ }
+}
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
new file mode 100644
index 0000000..966179b
--- /dev/null
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.soundtrigger;
+
+import java.util.Random;
+import java.util.UUID;
+
+import android.app.Activity;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+public class TestSoundTriggerActivity extends Activity {
+ private static final String TAG = "TestSoundTriggerActivity";
+ private static final boolean DBG = true;
+
+ private SoundTriggerUtil mSoundTriggerUtil;
+ private Random mRandom;
+ private UUID mModelUuid = UUID.randomUUID();
+ private UUID mModelUuid2 = UUID.randomUUID();
+ private UUID mVendorUuid = UUID.randomUUID();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ if (DBG) Log.d(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ mSoundTriggerUtil = new SoundTriggerUtil(this);
+ mRandom = new Random();
+ }
+
+ /**
+ * Called when the user clicks the enroll button.
+ * Performs a fresh enrollment.
+ */
+ public void onEnrollButtonClicked(View v) {
+ // Generate a fake model to push.
+ byte[] data = new byte[1024];
+ mRandom.nextBytes(data);
+ GenericSoundModel model = new GenericSoundModel(mModelUuid, mVendorUuid, data);
+
+ boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(model);
+ if (status) {
+ Toast.makeText(
+ this, "Successfully created sound trigger model UUID=" + mModelUuid, Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ Toast.makeText(this, "Failed to enroll!!!" + mModelUuid, Toast.LENGTH_SHORT).show();
+ }
+
+ // Test the SoundManager API.
+ SoundTriggerManager.Model tmpModel = SoundTriggerManager.Model.create(mModelUuid2,
+ mVendorUuid, data);
+ mSoundTriggerUtil.addOrUpdateSoundModel(tmpModel);
+ }
+
+ /**
+ * Called when the user clicks the un-enroll button.
+ * Clears the enrollment information for the user.
+ */
+ public void onUnEnrollButtonClicked(View v) {
+ GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+ if (soundModel == null) {
+ Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid);
+ if (status) {
+ Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid,
+ Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ Toast.makeText(this, "Failed to delete sound model!!!", Toast.LENGTH_SHORT).show();
+ }
+ mSoundTriggerUtil.deleteSoundModelUsingManager(mModelUuid2);
+ }
+
+ /**
+ * Called when the user clicks the re-enroll button.
+ * Uses the previously enrolled sound model and makes changes to it before pushing it back.
+ */
+ public void onReEnrollButtonClicked(View v) {
+ GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+ if (soundModel == null) {
+ Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ // Generate a fake model to push.
+ byte[] data = new byte[2048];
+ mRandom.nextBytes(data);
+ GenericSoundModel updated = new GenericSoundModel(soundModel.uuid,
+ soundModel.vendorUuid, data);
+ boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(updated);
+ if (status) {
+ Toast.makeText(this, "Successfully re-enrolled, model UUID=" + updated.uuid,
+ Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ Toast.makeText(this, "Failed to re-enroll!!!", Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
new file mode 100644
index 0000000..e0e3f03
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#00ff0000"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
new file mode 100644
index 0000000..cfb1236
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
new file mode 100644
index 0000000..18274b9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#f00"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
new file mode 100644
index 0000000..ef6fd70
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:startColor="?android:attr/colorPrimary"
+ android:type="radial">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
new file mode 100644
index 0000000..51b0e17
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:startColor="#ffffffff"
+ android:type="radial">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
new file mode 100644
index 0000000..8caa1b4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:type="radial">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
new file mode 100644
index 0000000..e1fbd10
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep">
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
new file mode 100644
index 0000000..332b938
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
new file mode 100644
index 0000000..3931288
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:type="sweep">
+ <item android:offset="-0.3" android:color="#f00"/>
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#0f0"/>
+ <item android:offset="0.6" android:color="#00f"/>
+ <item android:offset="0.7" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="1.5" android:color="#00f"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient.xml b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
new file mode 100644
index 0000000..cb324c9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
new file mode 100644
index 0000000..15d948c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
new file mode 100644
index 0000000..fda2b88
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#2f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
new file mode 100644
index 0000000..45d88b5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorPrimary" android:state_pressed="true" />
+ <item android:color="?android:attr/colorControlActivated" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
new file mode 100644
index 0000000..0e2467f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#f00" android:state_pressed="true" />
+ <item android:color="#00f" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
new file mode 100644
index 0000000..16251c8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorControlActivated" android:state_pressed="true" />
+ <item android:color="?android:attr/colorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
new file mode 100644
index 0000000..7e6c8ce
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#00f" android:state_pressed="true" />
+ <item android:color="#f00" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 2be99be..89afde2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -27,8 +27,8 @@
<path
android:name="box1"
android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
- android:fillColor="?android:attr/colorControlNormal"
- android:strokeColor="?android:attr/colorControlNormal"
+ android:fillColor="?android:attr/colorPrimary"
+ android:strokeColor="?android:attr/colorPrimary"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
new file mode 100644
index 0000000..d67aca7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="@color/fill_gradient_linear"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
new file mode 100644
index 0000000..abf3c7a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
new file mode 100644
index 0000000..5f9726f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item_overlap"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item_short"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item_long"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
new file mode 100644
index 0000000..9f08fe8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24" >
+
+ <path
+ android:fillColor="@color/vector_icon_fill_state_list_simple"
+ android:strokeColor="@color/vector_icon_stroke_state_list_simple"
+ android:strokeWidth="3"
+ android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
new file mode 100644
index 0000000..b1ed850
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24" >
+
+ <path
+ android:fillColor="@color/vector_icon_fill_state_list"
+ android:strokeColor="@color/vector_icon_stroke_state_list"
+ android:strokeWidth="3"
+ android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index b4a93f6..7172147 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,6 +35,11 @@
public class VectorDrawablePerformance extends Activity {
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
+ R.drawable.vector_icon_gradient_1,
+ R.drawable.vector_icon_gradient_2,
+ R.drawable.vector_icon_gradient_3,
+ R.drawable.vector_icon_state_list_simple,
+ R.drawable.vector_icon_state_list_theme,
R.drawable.vector_drawable01,
R.drawable.vector_drawable02,
R.drawable.vector_drawable03,
@@ -102,7 +107,7 @@
ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this);
scrollView.addView(container);
- container.setColumnCount(5);
+ container.setColumnCount(4);
Resources res = this.getResources();
container.setBackgroundColor(0xFF888888);
VectorDrawable []d = new VectorDrawable[icon.length];
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index b78fd49..0286506 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY, false, false);
+ Configuration.EMPTY, 0, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -103,7 +103,7 @@
}
try {
- mWm.setAppTask(null, 0, INVALID_STACK_ID, null, null);
+ mWm.setAppTask(null, 0, INVALID_STACK_ID, null, null, 0, false);
fail("IWindowManager.setAppGroupId did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 9f0153a..38eb5ee 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -77,7 +77,8 @@
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
+ Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15)
+ throws RemoteException {
// TODO Auto-generated method stub
}
@@ -322,7 +323,8 @@
}
@Override
- public void setAppTask(IBinder arg0, int arg1, int arg2, Rect arg3, Configuration arg4)
+ public void setAppTask(IBinder arg0, int arg1, int arg2, Rect arg3, Configuration arg4,
+ int arg5, boolean arg6)
throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index a3f3821..2000fbc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -50,7 +50,7 @@
@Override
public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
- boolean b, Configuration configuration, Rect rect7) throws RemoteException {
+ boolean b, Configuration configuration, Rect rect7, boolean b2) throws RemoteException {
// pass for now.
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index dc06789..1f05339 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -18,7 +18,9 @@
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Describes information about a detected access point. In addition
@@ -301,6 +303,12 @@
/**
* @hide
+ * anqp lines from supplicant BSS response
+ */
+ public List<String> anqpLines;
+
+ /**
+ * @hide
* storing the raw bytes of full result IEs
**/
public byte[] bytes;
@@ -518,6 +526,15 @@
} else {
dest.writeInt(0);
}
+
+ if (anqpLines != null) {
+ dest.writeInt(anqpLines.size());
+ for (int i = 0; i < anqpLines.size(); i++) {
+ dest.writeString(anqpLines.get(i));
+ }
+ } else {
+ dest.writeInt(0);
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -565,6 +582,14 @@
in.readByteArray(sr.informationElements[i].bytes);
}
}
+
+ n = in.readInt();
+ if (n != 0) {
+ sr.anqpLines = new ArrayList<String>();
+ for (int i = 0; i < n; i++) {
+ sr.anqpLines.add(in.readString());
+ }
+ }
return sr;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 274e985..4c22460 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -704,24 +704,6 @@
*/
public int numUserTriggeredJoinAttempts;
- /**
- * @hide
- * Connect choices
- *
- * remember the keys identifying the known WifiConfiguration over which this configuration
- * was preferred by user or a "WiFi Network Management app", that is,
- * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
- * was visible to the user:
- * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
- *
- * The integer represents the configuration's RSSI at that time (useful?)
- *
- * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
- * the exact algorithm still fluctuating as of 5/7/2014
- *
- */
- public HashMap<String, Integer> connectChoices;
-
/** @hide
* Boost given to RSSI on a home network for the purpose of calculating the score
* This adds stickiness to home networks, as defined by:
@@ -831,6 +813,16 @@
*/
public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
+ /**
+ * This constant indicates the current configuration has connect choice set
+ */
+ private static final int CONNECT_CHOICE_EXISTS = 1;
+
+ /**
+ * This constant indicates the current configuration does not have connect choice set
+ */
+ private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
+
// fields for QualityNetwork Selection
/**
* Network selection status, should be in one of three status: enable, temporaily disabled
@@ -854,7 +846,128 @@
private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
/**
- * return current Quality network selection status in String (for debug purpose)
+ * Connect Choice over this configuration
+ *
+ * When current wifi configuration is visible to the user but user explicitly choose to
+ * connect to another network X, the another networks X's configure key will be stored here.
+ * We will consider user has a preference of X over this network. And in the future,
+ * network selection will always give X a higher preference over this configuration.
+ * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+ */
+ private String mConnectChoice;
+
+ /**
+ * The system timestamp when we records the connectChoice. This value is obtained from
+ * System.currentTimeMillis
+ */
+ private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+ /**
+ * Used to cache the temporary candidate during the network selection procedure. It will be
+ * kept updating once a new scan result has a higher score than current one
+ */
+ private ScanResult mCandidate;
+
+ /**
+ * Used to cache the score of the current temporary candidate during the network
+ * selection procedure.
+ */
+ private int mCandidateScore;
+
+ /**
+ * Indicate whether this network is visible in latest Qualified Network Selection. This
+ * means there is scan result found related to this Configuration and meet the minimum
+ * requirement. The saved network need not join latest Qualified Network Selection. For
+ * example, it is disabled. True means network is visible in latest Qualified Network
+ * Selection and false means network is invisible
+ */
+ private boolean mSeenInLastQualifiedNetworkSelection;
+
+ /**
+ * set whether this network is visible in latest Qualified Network Selection
+ * @param seen value set to candidate
+ */
+ public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
+ mSeenInLastQualifiedNetworkSelection = seen;
+ }
+
+ /**
+ * get whether this network is visible in latest Qualified Network Selection
+ * @return returns true -- network is visible in latest Qualified Network Selection
+ * false -- network is invisible in latest Qualified Network Selection
+ */
+ public boolean getSeenInLastQualifiedNetworkSelection() {
+ return mSeenInLastQualifiedNetworkSelection;
+ }
+ /**
+ * set the temporary candidate of current network selection procedure
+ * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+ */
+ public void setCandidate(ScanResult scanCandidate) {
+ mCandidate = scanCandidate;
+ }
+
+ /**
+ * get the temporary candidate of current network selection procedure
+ * @return returns {@link ScanResult} temporary candidate of current network selection
+ * procedure
+ */
+ public ScanResult getCandidate() {
+ return mCandidate;
+ }
+
+ /**
+ * set the score of the temporary candidate of current network selection procedure
+ * @param score value set to mCandidateScore
+ */
+ public void setCandidateScore(int score) {
+ mCandidateScore = score;
+ }
+
+ /**
+ * get the score of the temporary candidate of current network selection procedure
+ * @return returns score of the temporary candidate of current network selection procedure
+ */
+ public int getCandidateScore() {
+ return mCandidateScore;
+ }
+
+ /**
+ * get user preferred choice over this configuration
+ *@return returns configKey of user preferred choice over this configuration
+ */
+ public String getConnectChoice() {
+ return mConnectChoice;
+ }
+
+ /**
+ * set user preferred choice over this configuration
+ * @param newConnectChoice, the configKey of user preferred choice over this configuration
+ */
+ public void setConnectChoice(String newConnectChoice) {
+ mConnectChoice = newConnectChoice;
+ }
+
+ /**
+ * get the timeStamp when user select a choice over this configuration
+ * @return returns when current connectChoice is set (time from System.currentTimeMillis)
+ */
+ public long getConnectChoiceTimestamp() {
+ return mConnectChoiceTimestamp;
+ }
+
+ /**
+ * set the timeStamp when user select a choice over this configuration
+ * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
+ * be obtained from System.currentTimeMillis
+ */
+ public void setConnectChoiceTimestamp(long timeStamp) {
+ mConnectChoiceTimestamp = timeStamp;
+ }
+
+ /**
+ * get current Quality network selection status
+ * @return returns current Quality network selection status in String (for debug purpose)
*/
public String getNetworkStatusString() {
return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
@@ -874,6 +987,7 @@
}
}
/**
+ * get current network disable reason
* @return current network disable reason in String (for debug purpose)
*/
public String getNetworkDisableReasonString() {
@@ -882,6 +996,7 @@
/**
* get current network network selection status
+ * @return return current network network selection status
*/
public int getNetworkSelectionStatus() {
return mStatus;
@@ -901,12 +1016,14 @@
}
/**
- * return whether current network is permanently disabled
+ * @return returns whether current network is permanently disabled
*/
public boolean isNetworkPermanentlyDisabled() {
return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
}
+
/**
+ * set current networ work selection status
* @param status network selection status to set
*/
public void setNetworkSelectionStatus(int status) {
@@ -914,14 +1031,16 @@
mStatus = status;
}
}
+
/**
- * @return current network's disable reason
+ * @return returns current network's disable reason
*/
public int getNetworkSelectionDisableReason() {
return mNetworkSelectionDisableReason;
}
/**
+ * set Network disable reason
* @param reason Network disable reason
*/
public void setNetworkSelectionDisableReason(int reason) {
@@ -931,12 +1050,17 @@
throw new IllegalArgumentException("Illegal reason value: " + reason);
}
}
+
/**
- * @param reason whether current network is disabled by this reason
+ * check whether network is disabled by this reason
+ * @param reason a specific disable reason
+ * @return true -- network is disabled for this reason
+ * false -- network is not disabled for this reason
*/
public boolean isDisabledByReason(int reason) {
return mNetworkSelectionDisableReason == reason;
}
+
/**
* @param timeStamp Set when current network is disabled in millisecond since January 1,
* 1970 00:00:00.0 UTC
@@ -946,7 +1070,7 @@
}
/**
- * @return Get when current network is disabled in millisecond since January 1,
+ * @return returns when current network is disabled in millisecond since January 1,
* 1970 00:00:00.0 UTC
*/
public long getDisableTime() {
@@ -954,6 +1078,7 @@
}
/**
+ * get the disable counter of a specific reason
* @param reason specific failure reason
* @exception throw IllegalArgumentException for illegal input
* @return counter number for specific error reason.
@@ -992,6 +1117,7 @@
throw new IllegalArgumentException("Illegal reason value: " + reason);
}
}
+
/**
* clear the counter of a specific failure reason
* @hide
@@ -1005,6 +1131,7 @@
throw new IllegalArgumentException("Illegal reason value: " + reason);
}
}
+
/**
* clear all the failure reason counters
*/
@@ -1043,6 +1170,8 @@
}
mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+ setConnectChoice(source.getConnectChoice());
+ setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
}
public void writeToParcel(Parcel dest) {
@@ -1054,6 +1183,13 @@
}
dest.writeLong(getDisableTime());
dest.writeString(getNetworkSelectionBSSID());
+ if (getConnectChoice() != null) {
+ dest.writeInt(CONNECT_CHOICE_EXISTS);
+ dest.writeString(getConnectChoice());
+ dest.writeLong(getConnectChoiceTimestamp());
+ } else {
+ dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
+ }
}
public void readFromParcel(Parcel in) {
@@ -1065,6 +1201,13 @@
}
setDisableTime(in.readLong());
setNetworkSelectionBSSID(in.readString());
+ if (in.readInt() == CONNECT_CHOICE_EXISTS) {
+ setConnectChoice(in.readString());
+ setConnectChoiceTimestamp(in.readLong());
+ } else {
+ setConnectChoice(null);
+ setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+ }
}
}
@@ -1184,7 +1327,11 @@
}
}
}
-
+ if (mNetworkSelectionStatus.getConnectChoice() != null) {
+ sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
+ sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
+ .getConnectChoiceTimestamp());
+ }
if (this.numAssociation > 0) {
sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -1336,16 +1483,7 @@
sbuf.append('\n');
}
}
- if (this.connectChoices != null) {
- for(String key : this.connectChoices.keySet()) {
- Integer choice = this.connectChoices.get(key);
- if (choice != null) {
- sbuf.append(" choice: ").append(key);
- sbuf.append(" = ").append(choice);
- sbuf.append('\n');
- }
- }
- }
+
sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1632,11 +1770,6 @@
mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
- if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
- connectChoices = new HashMap<String, Integer>();
- connectChoices.putAll(source.connectChoices);
- }
-
if ((source.linkedConfigurations != null)
&& (source.linkedConfigurations.size() > 0)) {
linkedConfigurations = new HashMap<String, Integer>();
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ff3d29f..ec9e462 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -43,7 +43,8 @@
void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
void subscribe(int sessionId, in SubscribeData subscribeData,
in SubscribeSettings subscribeSettings);
- void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength);
+ void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength,
+ int messageId);
void stopSession(int sessionId);
void destroySession(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
index 773f83b..50c34d9 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
@@ -32,7 +32,7 @@
void onMatch(int peerId, in byte[] serviceSpecificInfo,
int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
- void onMessageSendSuccess();
- void onMessageSendFail(int reason);
+ void onMessageSendSuccess(int messageId);
+ void onMessageSendFail(int messageId, int reason);
void onMessageReceived(int peerId, in byte[] message, int messageLength);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 877f993..cb82268 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -319,13 +319,14 @@
/**
* {@hide}
*/
- public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength) {
+ public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+ int messageId) {
try {
if (VDBG) {
Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
- + ", messageLength=" + messageLength);
+ + ", messageLength=" + messageLength + ", messageId=" + messageId);
}
- mService.sendMessage(sessionId, peerId, message, messageLength);
+ mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
} catch (RemoteException e) {
Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c6b384e..d0a9410 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -103,8 +103,11 @@
* @param message The message to be transmitted.
* @param messageLength The number of bytes from the {@code message} to be
* transmitted.
+ * @param messageId An arbitrary integer used by the caller to identify the
+ * message. The same integer ID will be returned in the callbacks
+ * indicated message send success or failure.
*/
- public void sendMessage(int peerId, byte[] message, int messageLength) {
- mManager.sendMessage(mSessionId, peerId, message, messageLength);
+ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+ mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
}
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index c9d08c7..d5e59f0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -210,10 +210,10 @@
msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
break;
case LISTEN_MESSAGE_SEND_SUCCESS:
- WifiNanSessionListener.this.onMessageSendSuccess();
+ WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1);
break;
case LISTEN_MESSAGE_SEND_FAIL:
- WifiNanSessionListener.this.onMessageSendFail(msg.arg1);
+ WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2);
break;
case LISTEN_MESSAGE_RECEIVED:
WifiNanSessionListener.this.onMessageReceived(msg.arg2,
@@ -306,7 +306,7 @@
* {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
* never both.
*/
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
}
@@ -325,7 +325,7 @@
* @param reason The failure reason using {@code NanSessionListener.FAIL_*}
* codes.
*/
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
}
@@ -401,19 +401,21 @@
}
@Override
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess");
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+ msg.arg1 = messageId;
mHandler.sendMessage(msg);
}
@Override
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
- msg.arg1 = reason;
+ msg.arg1 = messageId;
+ msg.arg2 = reason;
mHandler.sendMessage(msg);
}